From 2b1812f900ff6f603a0c44e7af8aa0f68ef4fdf5 Mon Sep 17 00:00:00 2001 From: tkellner Date: Mon, 11 Jul 2011 14:04:36 +0000 Subject: Tentative change for ACOS card handling git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@943 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- smcc/src/main/java/at/gv/egiz/smcc/ACOSATCard.java | 161 ++++ smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java | 820 +++++++++++++++++---- .../main/java/at/gv/egiz/smcc/ACOSLIESignCard.java | 56 +- .../java/at/gv/egiz/smcc/AbstractACOSCard.java | 644 ---------------- .../egiz/smcc/AbstractACOSCardInfoboxHandler.java | 42 ++ 5 files changed, 910 insertions(+), 813 deletions(-) create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ACOSATCard.java delete mode 100644 smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCard.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/AbstractACOSCardInfoboxHandler.java 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; +} -- cgit v1.2.3