diff options
author | tkellner <tkellner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2011-07-11 14:04:36 +0000 |
---|---|---|
committer | tkellner <tkellner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2011-07-11 14:04:36 +0000 |
commit | 2b1812f900ff6f603a0c44e7af8aa0f68ef4fdf5 (patch) | |
tree | addbbe685a100dd9ca7b30de53f990522be5f1ed /smcc/src/main/java/at/gv/egiz | |
parent | c33d230abbbf08682c5dc6afd915030cb7be50f9 (diff) | |
download | mocca-2b1812f900ff6f603a0c44e7af8aa0f68ef4fdf5.tar.gz mocca-2b1812f900ff6f603a0c44e7af8aa0f68ef4fdf5.tar.bz2 mocca-2b1812f900ff6f603a0c44e7af8aa0f68ef4fdf5.zip |
Tentative change for ACOS card handling
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@943 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
Diffstat (limited to 'smcc/src/main/java/at/gv/egiz')
5 files changed, 910 insertions, 813 deletions
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSATCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSATCard.java new file mode 100644 index 00000000..adee7e3b --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSATCard.java @@ -0,0 +1,161 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.smcc; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import java.io.IOException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.TransparentFileInputStream; + +public class ACOSATCard extends AbstractACOSCardInfoboxHandler { + + public ACOSATCard(ACOSCard acoscard) { + super(acoscard); + } + + private final Logger log = LoggerFactory.getLogger(ACOSATCard.class); + + @Override + @Exclusive + public byte[] getInfobox(String infobox, PINGUI provider, String domainId) + throws SignatureCardException, InterruptedException { + + if ("IdentityLink".equals(infobox)) { + if (_acoscard.getAppVersion() < 2) { + return getIdentityLinkV1(provider, domainId); + } else { + return getIdentityLinkV2(provider, domainId); + } + } else { + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + } + + protected byte[] getIdentityLinkV1(PINGUI provider, String domainId) + throws SignatureCardException, InterruptedException { + + try { + CardChannel channel = _acoscard.getCardChannel(); + // SELECT application + _acoscard.execSELECT_AID(channel, ACOSCard.AID_DEC); + // SELECT file + byte[] fcx = _acoscard.execSELECT_FID(channel, ACOSCard.EF_INFOBOX); + int maxSize = ISO7816Utils.getLengthFromFCx(fcx); + log.debug("Size of selected file = {}.", maxSize); + // READ BINARY + while (true) { + try { + byte[] idLink = ISO7816Utils.readTransparentFileTLV( + channel, maxSize, (byte) 0x30); + if (idLink != null) { + return idLink; + } else { + throw new NotActivatedException(); + } + } catch (SecurityStatusNotSatisfiedException e) { + _acoscard.verifyPINLoop(channel, _acoscard.infPinInfo, provider); + } + } + + } catch (FileNotFoundException e) { + throw new NotActivatedException(); + } catch (CardException e) { + log.info("Faild to get infobox.", e); + throw new SignatureCardException(e); + } + + } + + protected byte[] getIdentityLinkV2(PINGUI provider, String domainId) + throws SignatureCardException, InterruptedException { + + try { + CardChannel channel = _acoscard.getCardChannel(); + // SELECT application + _acoscard.execSELECT_AID(channel, ACOSCard.AID_DEC); + // SELECT file + _acoscard.execSELECT_FID(channel, ACOSCard.EF_INFOBOX); + + // READ BINARY + TransparentFileInputStream is = ISO7816Utils + .openTransparentFileInputStream(channel, -1); + InfoboxContainer infoboxContainer = new InfoboxContainer(is, + (byte) 0x30); + + for (Infobox box : infoboxContainer.getInfoboxes()) { + if (box.getTag() == 0x01) { + if (box.isEncrypted()) { + + _acoscard.execMSE(channel, 0x41, 0xb8, new byte[] { (byte) 0x84, + (byte) 0x01, (byte) 0x88, (byte) 0x80, + (byte) 0x01, (byte) 0x02 }); + + byte[] plainKey = null; + + while (true) { + try { + plainKey = _acoscard.execPSO_DECIPHER(channel, box + .getEncryptedKey()); + break; + } catch (SecurityStatusNotSatisfiedException e) { + _acoscard.verifyPINLoop(channel, _acoscard.decPinInfo, provider); + } + } + + return box.decipher(plainKey); + + } else { + return box.getData(); + } + } + } + + // empty + throw new NotActivatedException(); + + } catch (FileNotFoundException e) { + throw new NotActivatedException(); + } catch (CardException e) { + log.info("Faild to get infobox.", e); + throw new SignatureCardException(e); + } catch (IOException e) { + if (e.getCause() instanceof SignatureCardException) { + throw (SignatureCardException) e.getCause(); + } else { + throw new SignatureCardException(e); + } + } + + } + +} 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 105ef13c..e42370dc 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -1,157 +1,663 @@ -/* - * Copyright 2011 by Graz University of Technology, Austria - * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint - * initiative of the Federal Chancellery Austria and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - */ - -package at.gv.egiz.smcc; - -import at.gv.egiz.smcc.pin.gui.PINGUI; -import java.io.IOException; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.TransparentFileInputStream; - -public class ACOSCard extends AbstractACOSCard { - - private final Logger log = LoggerFactory.getLogger(ACOSCard.class); - - @Override - @Exclusive - public byte[] getInfobox(String infobox, PINGUI provider, String domainId) - throws SignatureCardException, InterruptedException { - - if ("IdentityLink".equals(infobox)) { - if (getAppVersion() < 2) { - return getIdentityLinkV1(provider, domainId); - } else { - return getIdentityLinkV2(provider, domainId); - } - } else { - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - } - - } - - protected byte[] getIdentityLinkV1(PINGUI provider, String domainId) - throws SignatureCardException, InterruptedException { - - try { - CardChannel channel = getCardChannel(); - // SELECT application - execSELECT_AID(channel, AID_DEC); - // SELECT file - byte[] fcx = execSELECT_FID(channel, EF_INFOBOX); - int maxSize = ISO7816Utils.getLengthFromFCx(fcx); - log.debug("Size of selected file = {}.", maxSize); - // READ BINARY - while (true) { - try { - byte[] idLink = ISO7816Utils.readTransparentFileTLV( - channel, maxSize, (byte) 0x30); - if (idLink != null) { - return idLink; - } else { - throw new NotActivatedException(); - } - } catch (SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, infPinInfo, provider); - } - } - - } catch (FileNotFoundException e) { - throw new NotActivatedException(); - } catch (CardException e) { - log.info("Faild to get infobox.", e); - throw new SignatureCardException(e); - } - - } - - protected byte[] getIdentityLinkV2(PINGUI provider, String domainId) - throws SignatureCardException, InterruptedException { - - try { - CardChannel channel = getCardChannel(); - // SELECT application - execSELECT_AID(channel, AID_DEC); - // SELECT file - execSELECT_FID(channel, EF_INFOBOX); - - // READ BINARY - TransparentFileInputStream is = ISO7816Utils - .openTransparentFileInputStream(channel, -1); - InfoboxContainer infoboxContainer = new InfoboxContainer(is, - (byte) 0x30); - - for (Infobox box : infoboxContainer.getInfoboxes()) { - if (box.getTag() == 0x01) { - if (box.isEncrypted()) { - - execMSE(channel, 0x41, 0xb8, new byte[] { (byte) 0x84, - (byte) 0x01, (byte) 0x88, (byte) 0x80, - (byte) 0x01, (byte) 0x02 }); - - byte[] plainKey = null; - - while (true) { - try { - plainKey = execPSO_DECIPHER(channel, box - .getEncryptedKey()); - break; - } catch (SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, decPinInfo, provider); - } - } - - return box.decipher(plainKey); - - } else { - return box.getData(); - } - } - } - - // empty - throw new NotActivatedException(); - - } catch (FileNotFoundException e) { - throw new NotActivatedException(); - } catch (CardException e) { - log.info("Faild to get infobox.", e); - throw new SignatureCardException(e); - } catch (IOException e) { - if (e.getCause() instanceof SignatureCardException) { - throw (SignatureCardException) e.getCause(); - } else { - throw new SignatureCardException(e); - } - } - - } - -} +/*
+ * Copyright 2011 by Graz University of Technology, Austria
+ * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint
+ * initiative of the Federal Chancellery Austria and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+package at.gv.egiz.smcc;
+
+import iaik.me.asn1.ASN1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
+import at.gv.egiz.smcc.util.ISO7816Utils;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import at.gv.egiz.smcc.util.TransparentFileInputStream;
+
+public class ACOSCard extends AbstractSignatureCard implements
+PINMgmtSignatureCard {
+
+ public static final byte[] AID_DEC = new byte[] { (byte) 0xA0, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x4E };
+
+ public static final byte[] DF_DEC = new byte[] { (byte) 0xdf, (byte) 0x71 };
+
+ public static final byte[] AID_SIG = new byte[] { (byte) 0xA0, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x43 };
+
+ public static final byte[] DF_SIG = new byte[] { (byte) 0xdf, (byte) 0x70 };
+
+ public static final byte[] EF_C_CH_EKEY = new byte[] { (byte) 0xc0,
+ (byte) 0x01 };
+
+ public static final int EF_C_CH_EKEY_MAX_SIZE = 2000;
+
+ public static final byte[] EF_C_CH_DS = new byte[] { (byte) 0xc0, (byte) 0x02 };
+
+ public static final int EF_C_CH_DS_MAX_SIZE = 2000;
+
+ public static final byte[] EF_PK_CH_EKEY = new byte[] { (byte) 0xb0,
+ (byte) 0x01 };
+
+ public static final byte[] EF_INFOBOX = new byte[] { (byte) 0xc0, (byte) 0x02 };
+
+ public static final byte[] EF_INFO = new byte[] { (byte) 0xd0, (byte) 0x02 };
+
+ public static final int EF_INFOBOX_MAX_SIZE = 1500;
+
+ public static final byte KID_PIN_SIG = (byte) 0x81;
+
+ public static final byte KID_PUK_SIG = (byte) 0x83;
+
+ public static final byte KID_PIN_DEC = (byte) 0x81;
+
+ public static final byte KID_PUK_DEC = (byte) 0x82;
+
+ public static final byte KID_PIN_INF = (byte) 0x83;
+
+ public static final byte KID_PUK_INF = (byte) 0x84;
+
+ public static final byte[] DST_SIG = new byte[] { (byte) 0x84, (byte) 0x01, // tag
+ // ,
+ // length
+ // (
+ // key
+ // ID
+ // )
+ (byte) 0x88, // SK.CH.SIGN
+ (byte) 0x80, (byte) 0x01, // tag, length (algorithm ID)
+ (byte) 0x14 // ECDSA
+ };
+
+ public static final byte[] AT_DEC = new byte[] { (byte) 0x84, (byte) 0x01, // tag
+ // ,
+ // length
+ // (
+ // key
+ // ID
+ // )
+ (byte) 0x88, // SK.CH.EKEY
+ (byte) 0x80, (byte) 0x01, // tag, length (algorithm ID)
+ (byte) 0x01 // RSA // TODO: Not verified yet
+ };
+
+ private final Logger log = LoggerFactory.getLogger(ACOSCard.class);
+
+ protected PinInfo decPinInfo, sigPinInfo, infPinInfo;
+
+ private AbstractACOSCardInfoboxHandler _infoboxHandler;
+
+ /**
+ * The version of the card's digital signature application.
+ */
+ protected int appVersion = -1;
+
+ @Override
+ public void init(Card card, CardTerminal cardTerminal) {
+ super.init(card, cardTerminal);
+
+ // determine application version
+ try {
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, AID_SIG);
+ // SELECT file
+ execSELECT_FID(channel, EF_INFO);
+ // READ BINARY
+ TransparentFileInputStream is = ISO7816Utils.openTransparentFileInputStream(channel, 8);
+ appVersion = is.read();
+ log.info("a-sign premium application version = " + appVersion);
+ } catch (FileNotFoundException e) {
+ appVersion = 1;
+ log.info("a-sign premium application version = " + appVersion);
+ } catch (SignatureCardException e) {
+ log.warn("Failed to execute command.", e);
+ appVersion = 0;
+ } catch (IOException e) {
+ log.warn("Failed to execute command.", e);
+ appVersion = 0;
+ } catch (CardException e) {
+ log.warn("Failed to execute command.", e);
+ appVersion = 0;
+ }
+
+ decPinInfo = new PinInfo(0, 8, "[0-9]",
+ "at/gv/egiz/smcc/ACOSCard", "dec.pin", KID_PIN_DEC, AID_DEC, 10);
+
+ sigPinInfo = new PinInfo(0, 8, "[0-9]",
+ "at/gv/egiz/smcc/ACOSCard", "sig.pin", KID_PIN_SIG, AID_SIG, 10);
+
+ infPinInfo= new PinInfo(0, 8, "[0-9]",
+ "at/gv/egiz/smcc/ACOSCard", "inf.pin", KID_PIN_INF, AID_DEC, 10);
+
+ if (SignatureCardFactory.ENFORCE_RECOMMENDED_PIN_LENGTH) {
+ decPinInfo.setRecLength(4);
+ sigPinInfo.setRecLength(6);
+ infPinInfo.setRecLength(4);
+ }
+
+ // read signing certificate to distinguish between Austrian and Liechtenstein cards
+ try {
+ byte[] cert = getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR, null);
+
+ ASN1 asn1 = new ASN1(cert);
+
+ String countryID = asn1.getElementAt(0).getElementAt(3).getElementAt(0).getElementAt(0).getElementAt(1).gvString();
+
+ if(countryID.equalsIgnoreCase("LI")) {
+ log.debug("Identified lisign card.");
+ _infoboxHandler = new ACOSLIESignCard(this);
+ } else {
+ log.debug("No lisign card - default to ACOS Austria.");
+ _infoboxHandler = new ACOSATCard(this);
+ }
+ } catch (SignatureCardException e) {
+ log.warn("Cannot determine card type by certificate. Using default.", e);
+ _infoboxHandler = new ACOSATCard(this);
+ } catch (IOException e) {
+ log.warn("Cannot determine card type by certificate. Using default.", e);
+ _infoboxHandler = new ACOSATCard(this);
+ } catch (RuntimeException e) {
+ log.warn("Cannot determine card type by certificate. Using default.", e);
+ _infoboxHandler = new ACOSATCard(this);
+ }
+ }
+
+ @Override
+ @Exclusive
+ public byte[] getCertificate(KeyboxName keyboxName, PINGUI provider)
+ throws SignatureCardException {
+
+ byte[] aid;
+ byte[] fid;
+ if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
+ aid = AID_SIG;
+ fid = EF_C_CH_DS;
+ } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
+ aid = AID_DEC;
+ fid = EF_C_CH_EKEY;
+ } else {
+ throw new IllegalArgumentException("Keybox " + keyboxName
+ + " not supported.");
+ }
+
+ try {
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, aid);
+ // SELECT file
+ byte[] fcx = execSELECT_FID(channel, fid);
+ int maxSize = -1;
+ if (getAppVersion() < 2) {
+ maxSize = ISO7816Utils.getLengthFromFCx(fcx);
+ log.debug("Size of selected file = {}.", maxSize);
+ }
+ // READ BINARY
+ byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, maxSize, (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 {
+
+ return _infoboxHandler.getInfobox(infobox, provider, domainId);
+ }
+
+
+
+ @Override
+ @Exclusive
+ public byte[] createSignature(InputStream input, KeyboxName keyboxName,
+ PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException {
+
+ ByteArrayOutputStream dst = new ByteArrayOutputStream();
+ // key ID
+ dst.write(new byte[]{(byte) 0x84, (byte) 0x01, (byte) 0x88});
+ // algorithm ID
+ dst.write(new byte[]{(byte) 0x80, (byte) 0x01});
+
+ MessageDigest md;
+ try {
+ if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
+ && (alg == null || "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1".equals(alg))) {
+ dst.write((byte) 0x14); // SHA-1/ECC
+ md = MessageDigest.getInstance("SHA-1");
+ } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)
+ && (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1".equals(alg))) {
+ dst.write((byte) 0x12); // SHA-1 with padding according to PKCS#1 block type 01
+ md = MessageDigest.getInstance("SHA-1");
+ } else if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
+ && appVersion >= 2
+ && "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256".equals(alg)) {
+ dst.write((byte) 0x44); // SHA-256/ECC
+ md = MessageDigest.getInstance("SHA256");
+ } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)
+ && appVersion >= 2
+ && "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256".equals(alg)) {
+ dst.write((byte) 0x41); // SHA-256 with padding according to PKCS#1
+ md = MessageDigest.getInstance("SHA256");
+ } else {
+ throw new SignatureCardException("Card does not support signature algorithm " + alg + ".");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Failed to get MessageDigest.", e);
+ throw new SignatureCardException(e);
+ }
+
+ byte[] digest = new byte[md.getDigestLength()];
+ for (int l; (l = input.read(digest)) != -1;) {
+ md.update(digest, 0, l);
+ }
+ digest = md.digest();
+
+ try {
+
+ CardChannel channel = getCardChannel();
+
+ if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
+
+ // SELECT application
+ execSELECT_AID(channel, AID_SIG);
+ // MANAGE SECURITY ENVIRONMENT : SET DST
+ execMSE(channel, 0x41, 0xb6, dst.toByteArray());
+ // VERIFY
+ verifyPINLoop(channel, sigPinInfo, provider);
+ // PERFORM SECURITY OPERATION : HASH
+ execPSO_HASH(channel, digest);
+ // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATRE
+ return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel);
+
+ } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
+
+ // SELECT application
+ execSELECT_AID(channel, AID_DEC);
+ // MANAGE SECURITY ENVIRONMENT : SET AT
+ execMSE(channel, 0x41, 0xa4, AT_DEC);
+
+ while (true) {
+ try {
+ // INTERNAL AUTHENTICATE
+ return execINTERNAL_AUTHENTICATE(channel, digest);
+ } catch (SecurityStatusNotSatisfiedException e) {
+ verifyPINLoop(channel, decPinInfo, provider);
+ }
+ }
+
+ } else {
+ throw new IllegalArgumentException("KeyboxName '" + keyboxName
+ + "' not supported.");
+ }
+
+ } catch (CardException e) {
+ log.warn("Failed to execute command.", e);
+ throw new SignatureCardException("Failed to access card.", e);
+ }
+
+ }
+
+ public int getAppVersion() {
+ return appVersion;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.pinInfo, at.gv.egiz.smcc.PINProvider)
+ */
+ @Override
+ public void verifyPIN(PinInfo pinInfo, PINGUI pinProvider)
+ throws LockedException, NotActivatedException, CancelledException,
+ TimeoutException, SignatureCardException, InterruptedException {
+
+ CardChannel channel = getCardChannel();
+
+ try {
+ // SELECT application
+ execSELECT_AID(channel, pinInfo.getContextAID());
+ // VERIFY
+ verifyPINLoop(channel, pinInfo, pinProvider);
+ } catch (CardException e) {
+ log.info("Failed to verify PIN.", e);
+ throw new SignatureCardException("Failed to verify PIN.", e);
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.pinInfo, at.gv.egiz.smcc.ChangePINProvider)
+ */
+ @Override
+ public void changePIN(PinInfo pinInfo, ModifyPINGUI pinProvider)
+ throws LockedException, NotActivatedException, CancelledException,
+ TimeoutException, SignatureCardException, InterruptedException {
+
+ CardChannel channel = getCardChannel();
+
+ try {
+ // SELECT application
+ execSELECT_AID(channel, pinInfo.getContextAID());
+ // CHANGE REFERENCE DATA
+ changePINLoop(channel, pinInfo, pinProvider);
+ } catch (CardException e) {
+ log.info("Failed to change PIN.", e);
+ throw new SignatureCardException("Failed to change PIN.", e);
+ }
+
+ }
+
+ @Override
+ public void activatePIN(PinInfo pinInfo, ModifyPINGUI pinGUI)
+ throws CancelledException, SignatureCardException, CancelledException,
+ TimeoutException, InterruptedException {
+ log.error("ACTIVATE PIN not supported by ACOS");
+ throw new SignatureCardException("PIN activation not supported by this card.");
+ }
+
+ @Override
+ public void unblockPIN(PinInfo pinInfo, ModifyPINGUI pinGUI)
+ throws CancelledException, SignatureCardException, InterruptedException {
+ throw new SignatureCardException("Unblock PIN not supported.");
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getpinInfos()
+ */
+ @Override
+ public PinInfo[] getPinInfos() throws SignatureCardException {
+
+ //check if card is activated
+ getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR, null);
+
+ if (appVersion < 2) {
+ return new PinInfo[] {decPinInfo, sigPinInfo, infPinInfo };
+ }
+ return new PinInfo[] {decPinInfo, sigPinInfo };
+ }
+
+ @Override
+ public String toString() {
+ return "a-sign premium (version " + getAppVersion() + ")";
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // PROTECTED METHODS (assume exclusive card access)
+ ////////////////////////////////////////////////////////////////////////
+
+ protected void verifyPINLoop(CardChannel channel, PinInfo spec, PINGUI provider)
+ throws InterruptedException, CardException, SignatureCardException {
+
+ int retries = -1;
+ do {
+ retries = verifyPIN(channel, spec, provider, retries);
+ } while (retries > 0);
+ }
+
+ protected void changePINLoop(CardChannel channel, PinInfo spec, ModifyPINGUI provider)
+ throws InterruptedException, CardException, SignatureCardException {
+
+ int retries = -1;
+ do {
+ retries = changePIN(channel, spec, provider, retries);
+ } while (retries > 0);
+ }
+
+ protected int verifyPIN(CardChannel channel, PinInfo pinInfo,
+ PINGUI provider, int retries) throws InterruptedException, CardException, SignatureCardException {
+
+ VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, pinInfo.getKID(), (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 },
+ 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
+
+ ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinInfo, retries);
+
+ if (resp.getSW() == 0x9000) {
+ pinInfo.setActive(pinInfo.maxRetries);
+ return -1;
+ }
+ if (resp.getSW() >> 4 == 0x63c) {
+ pinInfo.setActive(0x0f & resp.getSW());
+ return 0x0f & resp.getSW();
+ }
+
+ switch (resp.getSW()) {
+ case 0x6983:
+ // authentication method blocked
+ pinInfo.setBlocked();
+ throw new LockedException();
+
+ default:
+ String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW());
+ log.info(msg);
+ pinInfo.setUnknown();
+ throw new SignatureCardException(msg);
+ }
+
+ }
+
+ protected int changePIN(CardChannel channel, PinInfo pinInfo,
+ ModifyPINGUI pinProvider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException {
+
+ ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x24, (byte) 0x00, pinInfo.getKID(), (byte) 0x10,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ },
+ 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
+
+
+
+ ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinInfo, retries);
+
+ if (resp.getSW() == 0x9000) {
+ pinInfo.setActive(pinInfo.maxRetries);
+ return -1;
+ }
+ if (resp.getSW() >> 4 == 0x63c) {
+ pinInfo.setActive(0x0f & resp.getSW());
+ return 0x0f & resp.getSW();
+ }
+
+ switch (resp.getSW()) {
+ case 0x6983:
+ // authentication method blocked
+ pinInfo.setBlocked();
+ throw new LockedException();
+
+ default:
+ String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW());
+ log.info(msg);
+ pinInfo.setUnknown();
+ throw new SignatureCardException(msg);
+ }
+
+ }
+
+ protected void execMSE(CardChannel channel, int p1,
+ int p2, byte[] data) throws SignatureCardException, CardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x22, p1, p2, data));
+
+ if (resp.getSW() != 0x9000) {
+ String msg = "MSE failed: SW="
+ + Integer.toHexString(resp.getSW());
+ log.error(msg);
+ throw new SignatureCardException(msg);
+ }
+
+ }
+
+ protected byte[] execPSO_DECIPHER(CardChannel channel, byte [] cipher) throws CardException, SignatureCardException {
+
+ byte[] data = new byte[cipher.length + 1];
+ data[0] = 0x00;
+ System.arraycopy(cipher, 0, data, 1, cipher.length);
+ ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x2A, 0x80, 0x86, data, 256));
+ if (resp.getSW() == 0x6982) {
+ throw new SecurityStatusNotSatisfiedException();
+ } else if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException(
+ "PSO - DECIPHER failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ }
+
+ return resp.getData();
+
+ }
+
+ protected void execPSO_HASH(CardChannel channel, byte[] hash) throws CardException, SignatureCardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x2A, 0x90, 0x81, hash));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("PSO - HASH failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ }
+
+ }
+
+ protected byte[] execPSO_COMPUTE_DIGITAL_SIGNATURE(CardChannel channel) throws CardException,
+ SignatureCardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x2A, 0x9E, 0x9A, 256));
+ if (resp.getSW() == 0x6982) {
+ throw new SecurityStatusNotSatisfiedException();
+ }
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException(
+ "PSO - COMPUTE DIGITAL SIGNATRE failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ } else {
+ return resp.getData();
+ }
+
+ }
+
+ protected byte[] execINTERNAL_AUTHENTICATE(CardChannel channel, 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);
+
+ ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x88, 0x10, 0x00, data, 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();
+ }
+ }
+
+ protected byte[] execSELECT_AID(CardChannel channel, byte[] aid)
+ throws SignatureCardException, CardException {
+
+ 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 AID="
+ + SMCCHelper.toString(aid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ } else {
+ return resp.getBytes();
+ }
+
+ }
+
+ protected byte[] execSELECT_FID(CardChannel channel, byte[] fid)
+ throws SignatureCardException, CardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0xA4, 0x00, 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 application FID="
+ + SMCCHelper.toString(fid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.error(msg);
+ throw new SignatureCardException(msg);
+ } else {
+ return resp.getBytes();
+ }
+
+
+ }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSLIESignCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSLIESignCard.java index 52a140df..ba1e17c4 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSLIESignCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSLIESignCard.java @@ -1,17 +1,49 @@ +/*
+ * Copyright 2011 by Graz University of Technology, Austria
+ * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint
+ * initiative of the Federal Chancellery Austria and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
package at.gv.egiz.smcc;
import at.gv.egiz.smcc.pin.gui.PINGUI;
-public class ACOSLIESignCard extends AbstractACOSCard {
-
- @Override
- @Exclusive
- public byte[] getInfobox(String infobox, PINGUI provider, String domainId)
- throws SignatureCardException, InterruptedException {
-
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
-
- }
-
+/**
+ * @author tzefferer
+ * @author tkellner
+ *
+ */
+public class ACOSLIESignCard extends AbstractACOSCardInfoboxHandler {
+
+ public ACOSLIESignCard(ACOSCard acoscard) {
+ super(acoscard);
+ }
+
+ @Override
+ @Exclusive
+ public byte[] getInfobox(String infobox, PINGUI provider, String domainId)
+ throws SignatureCardException, InterruptedException {
+
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
+
+ }
+
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCard.java deleted file mode 100644 index 94846623..00000000 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCard.java +++ /dev/null @@ -1,644 +0,0 @@ -package at.gv.egiz.smcc;
-
-import iaik.me.asn1.ASN1;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import javax.smartcardio.Card;
-import javax.smartcardio.CardChannel;
-import javax.smartcardio.CardException;
-import javax.smartcardio.CardTerminal;
-import javax.smartcardio.CommandAPDU;
-import javax.smartcardio.ResponseAPDU;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
-import at.gv.egiz.smcc.pin.gui.PINGUI;
-import at.gv.egiz.smcc.util.ISO7816Utils;
-import at.gv.egiz.smcc.util.SMCCHelper;
-import at.gv.egiz.smcc.util.TransparentFileInputStream;
-
-public class AbstractACOSCard extends AbstractSignatureCard implements
-PINMgmtSignatureCard {
-
- public static final byte[] AID_DEC = new byte[] { (byte) 0xA0, (byte) 0x00,
- (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x4E };
-
- public static final byte[] DF_DEC = new byte[] { (byte) 0xdf, (byte) 0x71 };
-
- public static final byte[] AID_SIG = new byte[] { (byte) 0xA0, (byte) 0x00,
- (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x43 };
-
- public static final byte[] DF_SIG = new byte[] { (byte) 0xdf, (byte) 0x70 };
-
- public static final byte[] EF_C_CH_EKEY = new byte[] { (byte) 0xc0,
- (byte) 0x01 };
-
- public static final int EF_C_CH_EKEY_MAX_SIZE = 2000;
-
- public static final byte[] EF_C_CH_DS = new byte[] { (byte) 0xc0, (byte) 0x02 };
-
- public static final int EF_C_CH_DS_MAX_SIZE = 2000;
-
- public static final byte[] EF_PK_CH_EKEY = new byte[] { (byte) 0xb0,
- (byte) 0x01 };
-
- public static final byte[] EF_INFOBOX = new byte[] { (byte) 0xc0, (byte) 0x02 };
-
- public static final byte[] EF_INFO = new byte[] { (byte) 0xd0, (byte) 0x02 };
-
- public static final int EF_INFOBOX_MAX_SIZE = 1500;
-
- public static final byte KID_PIN_SIG = (byte) 0x81;
-
- public static final byte KID_PUK_SIG = (byte) 0x83;
-
- public static final byte KID_PIN_DEC = (byte) 0x81;
-
- public static final byte KID_PUK_DEC = (byte) 0x82;
-
- public static final byte KID_PIN_INF = (byte) 0x83;
-
- public static final byte KID_PUK_INF = (byte) 0x84;
-
- public static final byte[] DST_SIG = new byte[] { (byte) 0x84, (byte) 0x01, // tag
- // ,
- // length
- // (
- // key
- // ID
- // )
- (byte) 0x88, // SK.CH.SIGN
- (byte) 0x80, (byte) 0x01, // tag, length (algorithm ID)
- (byte) 0x14 // ECDSA
- };
-
- public static final byte[] AT_DEC = new byte[] { (byte) 0x84, (byte) 0x01, // tag
- // ,
- // length
- // (
- // key
- // ID
- // )
- (byte) 0x88, // SK.CH.EKEY
- (byte) 0x80, (byte) 0x01, // tag, length (algorithm ID)
- (byte) 0x01 // RSA // TODO: Not verified yet
- };
-
- private final Logger log = LoggerFactory.getLogger(AbstractACOSCard.class);
-
- protected PinInfo decPinInfo, sigPinInfo, infPinInfo;
-
- private AbstractACOSCard instance;
-
- /**
- * The version of the card's digital signature application.
- */
- protected int appVersion = -1;
-
- @Override
- public void init(Card card, CardTerminal cardTerminal) {
- super.init(card, cardTerminal);
-
- // determine application version
- try {
- CardChannel channel = getCardChannel();
- // SELECT application
- execSELECT_AID(channel, AID_SIG);
- // SELECT file
- execSELECT_FID(channel, EF_INFO);
- // READ BINARY
- TransparentFileInputStream is = ISO7816Utils.openTransparentFileInputStream(channel, 8);
- appVersion = is.read();
- log.info("a-sign premium application version = " + appVersion);
- } catch (FileNotFoundException e) {
- appVersion = 1;
- log.info("a-sign premium application version = " + appVersion);
- } catch (SignatureCardException e) {
- log.warn("Failed to execute command.", e);
- appVersion = 0;
- } catch (IOException e) {
- log.warn("Failed to execute command.", e);
- appVersion = 0;
- } catch (CardException e) {
- log.warn("Failed to execute command.", e);
- appVersion = 0;
- }
-
- decPinInfo = new PinInfo(0, 8, "[0-9]",
- "at/gv/egiz/smcc/ACOSCard", "dec.pin", KID_PIN_DEC, AID_DEC, 10);
-
- sigPinInfo = new PinInfo(0, 8, "[0-9]",
- "at/gv/egiz/smcc/ACOSCard", "sig.pin", KID_PIN_SIG, AID_SIG, 10);
-
- infPinInfo= new PinInfo(0, 8, "[0-9]",
- "at/gv/egiz/smcc/ACOSCard", "inf.pin", KID_PIN_INF, AID_DEC, 10);
-
- if (SignatureCardFactory.ENFORCE_RECOMMENDED_PIN_LENGTH) {
- decPinInfo.setRecLength(4);
- sigPinInfo.setRecLength(6);
- infPinInfo.setRecLength(4);
- }
-
- // read signing certificate to distinguish between Austrian and Liechtenstein cards
- try {
- byte[] cert = getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR, null);
-
- ASN1 asn1 = new ASN1(cert);
-
- String countryID = asn1.getElementAt(0).getElementAt(3).getElementAt(0).getElementAt(0).getElementAt(1).gvString();
-
- if(countryID.equalsIgnoreCase("LI")) {
-
- log.debug("Identified lisign card.");
- instance = new ACOSLIESignCard();
- } else {
-
- log.debug("No lisign card - default to ACOS Austria.");
- instance = new ACOSCard();
- }
-
- } catch (SignatureCardException e) {
- log.warn("Cannot determine card type by certificate. Using default.", e);
- instance = new ACOSCard();
- } catch (IOException e) {
- log.warn("Cannot determine card type by certificate. Using default.", e);
- instance = new ACOSCard();
- } catch (RuntimeException e) {
- log.warn("Cannot determine card type by certificate. Using default.", e);
- instance = new ACOSCard();
- }
-
- }
-
- @Override
- @Exclusive
- public byte[] getCertificate(KeyboxName keyboxName, PINGUI provider)
- throws SignatureCardException {
-
- byte[] aid;
- byte[] fid;
- if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
- aid = AID_SIG;
- fid = EF_C_CH_DS;
- } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
- aid = AID_DEC;
- fid = EF_C_CH_EKEY;
- } else {
- throw new IllegalArgumentException("Keybox " + keyboxName
- + " not supported.");
- }
-
- try {
- CardChannel channel = getCardChannel();
- // SELECT application
- execSELECT_AID(channel, aid);
- // SELECT file
- byte[] fcx = execSELECT_FID(channel, fid);
- int maxSize = -1;
- if (getAppVersion() < 2) {
- maxSize = ISO7816Utils.getLengthFromFCx(fcx);
- log.debug("Size of selected file = {}.", maxSize);
- }
- // READ BINARY
- byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, maxSize, (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 {
-
- return instance.getInfobox(infobox, provider, domainId);
- }
-
-
-
- @Override
- @Exclusive
- public byte[] createSignature(InputStream input, KeyboxName keyboxName,
- PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException {
-
- ByteArrayOutputStream dst = new ByteArrayOutputStream();
- // key ID
- dst.write(new byte[]{(byte) 0x84, (byte) 0x01, (byte) 0x88});
- // algorithm ID
- dst.write(new byte[]{(byte) 0x80, (byte) 0x01});
-
- MessageDigest md;
- try {
- if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
- && (alg == null || "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1".equals(alg))) {
- dst.write((byte) 0x14); // SHA-1/ECC
- md = MessageDigest.getInstance("SHA-1");
- } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)
- && (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1".equals(alg))) {
- dst.write((byte) 0x12); // SHA-1 with padding according to PKCS#1 block type 01
- md = MessageDigest.getInstance("SHA-1");
- } else if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
- && appVersion >= 2
- && "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256".equals(alg)) {
- dst.write((byte) 0x44); // SHA-256/ECC
- md = MessageDigest.getInstance("SHA256");
- } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)
- && appVersion >= 2
- && "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256".equals(alg)) {
- dst.write((byte) 0x41); // SHA-256 with padding according to PKCS#1
- md = MessageDigest.getInstance("SHA256");
- } else {
- throw new SignatureCardException("Card does not support signature algorithm " + alg + ".");
- }
- } catch (NoSuchAlgorithmException e) {
- log.error("Failed to get MessageDigest.", e);
- throw new SignatureCardException(e);
- }
-
- byte[] digest = new byte[md.getDigestLength()];
- for (int l; (l = input.read(digest)) != -1;) {
- md.update(digest, 0, l);
- }
- digest = md.digest();
-
- try {
-
- CardChannel channel = getCardChannel();
-
- if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
-
- // SELECT application
- execSELECT_AID(channel, AID_SIG);
- // MANAGE SECURITY ENVIRONMENT : SET DST
- execMSE(channel, 0x41, 0xb6, dst.toByteArray());
- // VERIFY
- verifyPINLoop(channel, sigPinInfo, provider);
- // PERFORM SECURITY OPERATION : HASH
- execPSO_HASH(channel, digest);
- // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATRE
- return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel);
-
- } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
-
- // SELECT application
- execSELECT_AID(channel, AID_DEC);
- // MANAGE SECURITY ENVIRONMENT : SET AT
- execMSE(channel, 0x41, 0xa4, AT_DEC);
-
- while (true) {
- try {
- // INTERNAL AUTHENTICATE
- return execINTERNAL_AUTHENTICATE(channel, digest);
- } catch (SecurityStatusNotSatisfiedException e) {
- verifyPINLoop(channel, decPinInfo, provider);
- }
- }
-
- } else {
- throw new IllegalArgumentException("KeyboxName '" + keyboxName
- + "' not supported.");
- }
-
- } catch (CardException e) {
- log.warn("Failed to execute command.", e);
- throw new SignatureCardException("Failed to access card.", e);
- }
-
- }
-
- public int getAppVersion() {
- return appVersion;
- }
-
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.pinInfo, at.gv.egiz.smcc.PINProvider)
- */
- @Override
- public void verifyPIN(PinInfo pinInfo, PINGUI pinProvider)
- throws LockedException, NotActivatedException, CancelledException,
- TimeoutException, SignatureCardException, InterruptedException {
-
- CardChannel channel = getCardChannel();
-
- try {
- // SELECT application
- execSELECT_AID(channel, pinInfo.getContextAID());
- // VERIFY
- verifyPINLoop(channel, pinInfo, pinProvider);
- } catch (CardException e) {
- log.info("Failed to verify PIN.", e);
- throw new SignatureCardException("Failed to verify PIN.", e);
- }
-
- }
-
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.pinInfo, at.gv.egiz.smcc.ChangePINProvider)
- */
- @Override
- public void changePIN(PinInfo pinInfo, ModifyPINGUI pinProvider)
- throws LockedException, NotActivatedException, CancelledException,
- TimeoutException, SignatureCardException, InterruptedException {
-
- CardChannel channel = getCardChannel();
-
- try {
- // SELECT application
- execSELECT_AID(channel, pinInfo.getContextAID());
- // CHANGE REFERENCE DATA
- changePINLoop(channel, pinInfo, pinProvider);
- } catch (CardException e) {
- log.info("Failed to change PIN.", e);
- throw new SignatureCardException("Failed to change PIN.", e);
- }
-
- }
-
- @Override
- public void activatePIN(PinInfo pinInfo, ModifyPINGUI pinGUI)
- throws CancelledException, SignatureCardException, CancelledException,
- TimeoutException, InterruptedException {
- log.error("ACTIVATE PIN not supported by ACOS");
- throw new SignatureCardException("PIN activation not supported by this card.");
- }
-
- @Override
- public void unblockPIN(PinInfo pinInfo, ModifyPINGUI pinGUI)
- throws CancelledException, SignatureCardException, InterruptedException {
- throw new SignatureCardException("Unblock PIN not supported.");
- }
-
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getpinInfos()
- */
- @Override
- public PinInfo[] getPinInfos() throws SignatureCardException {
-
- //check if card is activated
- getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR, null);
-
- if (appVersion < 2) {
- return new PinInfo[] {decPinInfo, sigPinInfo, infPinInfo };
- }
- return new PinInfo[] {decPinInfo, sigPinInfo };
- }
-
- @Override
- public String toString() {
- return "a-sign premium (version " + getAppVersion() + ")";
- }
-
- ////////////////////////////////////////////////////////////////////////
- // PROTECTED METHODS (assume exclusive card access)
- ////////////////////////////////////////////////////////////////////////
-
- protected void verifyPINLoop(CardChannel channel, PinInfo spec, PINGUI provider)
- throws InterruptedException, CardException, SignatureCardException {
-
- int retries = -1;
- do {
- retries = verifyPIN(channel, spec, provider, retries);
- } while (retries > 0);
- }
-
- protected void changePINLoop(CardChannel channel, PinInfo spec, ModifyPINGUI provider)
- throws InterruptedException, CardException, SignatureCardException {
-
- int retries = -1;
- do {
- retries = changePIN(channel, spec, provider, retries);
- } while (retries > 0);
- }
-
- protected int verifyPIN(CardChannel channel, PinInfo pinInfo,
- PINGUI provider, int retries) throws InterruptedException, CardException, SignatureCardException {
-
- VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(
- new byte[] {
- (byte) 0x00, (byte) 0x20, (byte) 0x00, pinInfo.getKID(), (byte) 0x08,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 },
- 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
-
- ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinInfo, retries);
-
- if (resp.getSW() == 0x9000) {
- pinInfo.setActive(pinInfo.maxRetries);
- return -1;
- }
- if (resp.getSW() >> 4 == 0x63c) {
- pinInfo.setActive(0x0f & resp.getSW());
- return 0x0f & resp.getSW();
- }
-
- switch (resp.getSW()) {
- case 0x6983:
- // authentication method blocked
- pinInfo.setBlocked();
- throw new LockedException();
-
- default:
- String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW());
- log.info(msg);
- pinInfo.setUnknown();
- throw new SignatureCardException(msg);
- }
-
- }
-
- protected int changePIN(CardChannel channel, PinInfo pinInfo,
- ModifyPINGUI pinProvider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException {
-
- ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec(
- new byte[] {
- (byte) 0x00, (byte) 0x24, (byte) 0x00, pinInfo.getKID(), (byte) 0x10,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
- },
- 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
-
-
-
- ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinInfo, retries);
-
- if (resp.getSW() == 0x9000) {
- pinInfo.setActive(pinInfo.maxRetries);
- return -1;
- }
- if (resp.getSW() >> 4 == 0x63c) {
- pinInfo.setActive(0x0f & resp.getSW());
- return 0x0f & resp.getSW();
- }
-
- switch (resp.getSW()) {
- case 0x6983:
- // authentication method blocked
- pinInfo.setBlocked();
- throw new LockedException();
-
- default:
- String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW());
- log.info(msg);
- pinInfo.setUnknown();
- throw new SignatureCardException(msg);
- }
-
- }
-
- protected void execMSE(CardChannel channel, int p1,
- int p2, byte[] data) throws SignatureCardException, CardException {
-
- ResponseAPDU resp = channel.transmit(
- new CommandAPDU(0x00, 0x22, p1, p2, data));
-
- if (resp.getSW() != 0x9000) {
- String msg = "MSE failed: SW="
- + Integer.toHexString(resp.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
- }
-
- }
-
- protected byte[] execPSO_DECIPHER(CardChannel channel, byte [] cipher) throws CardException, SignatureCardException {
-
- byte[] data = new byte[cipher.length + 1];
- data[0] = 0x00;
- System.arraycopy(cipher, 0, data, 1, cipher.length);
- ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x2A, 0x80, 0x86, data, 256));
- if (resp.getSW() == 0x6982) {
- throw new SecurityStatusNotSatisfiedException();
- } else if (resp.getSW() != 0x9000) {
- throw new SignatureCardException(
- "PSO - DECIPHER failed: SW="
- + Integer.toHexString(resp.getSW()));
- }
-
- return resp.getData();
-
- }
-
- protected void execPSO_HASH(CardChannel channel, byte[] hash) throws CardException, SignatureCardException {
-
- ResponseAPDU resp = channel.transmit(
- new CommandAPDU(0x00, 0x2A, 0x90, 0x81, hash));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("PSO - HASH failed: SW="
- + Integer.toHexString(resp.getSW()));
- }
-
- }
-
- protected byte[] execPSO_COMPUTE_DIGITAL_SIGNATURE(CardChannel channel) throws CardException,
- SignatureCardException {
-
- ResponseAPDU resp = channel.transmit(
- new CommandAPDU(0x00, 0x2A, 0x9E, 0x9A, 256));
- if (resp.getSW() == 0x6982) {
- throw new SecurityStatusNotSatisfiedException();
- }
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException(
- "PSO - COMPUTE DIGITAL SIGNATRE failed: SW="
- + Integer.toHexString(resp.getSW()));
- } else {
- return resp.getData();
- }
-
- }
-
- protected byte[] execINTERNAL_AUTHENTICATE(CardChannel channel, 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);
-
- ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x88, 0x10, 0x00, data, 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();
- }
- }
-
- protected byte[] execSELECT_AID(CardChannel channel, byte[] aid)
- throws SignatureCardException, CardException {
-
- 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 AID="
- + SMCCHelper.toString(aid) + " SW="
- + Integer.toHexString(resp.getSW()) + ".";
- log.info(msg);
- throw new SignatureCardException(msg);
- } else {
- return resp.getBytes();
- }
-
- }
-
- protected byte[] execSELECT_FID(CardChannel channel, byte[] fid)
- throws SignatureCardException, CardException {
-
- ResponseAPDU resp = channel.transmit(
- new CommandAPDU(0x00, 0xA4, 0x00, 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 application FID="
- + SMCCHelper.toString(fid) + " SW="
- + Integer.toHexString(resp.getSW()) + ".";
- log.error(msg);
- throw new SignatureCardException(msg);
- } else {
- return resp.getBytes();
- }
-
-
- }
-
-}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCardInfoboxHandler.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCardInfoboxHandler.java new file mode 100644 index 00000000..19f4d26e --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCardInfoboxHandler.java @@ -0,0 +1,42 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.smcc; + +import at.gv.egiz.smcc.pin.gui.PINGUI; + +/** + * @author tkellner + * + */ +public abstract class AbstractACOSCardInfoboxHandler { + protected ACOSCard _acoscard; + + public AbstractACOSCardInfoboxHandler(ACOSCard acoscard) + { + this._acoscard = acoscard; + } + + public abstract byte[] getInfobox(String infobox, PINGUI provider, String domainId) + throws SignatureCardException, InterruptedException; +} |