diff options
author | mcentner <mcentner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2010-05-05 15:29:01 +0000 |
---|---|---|
committer | mcentner <mcentner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2010-05-05 15:29:01 +0000 |
commit | b1c8641a63a67e3c64d948f9e8dce5c01e11e2dd (patch) | |
tree | 0883f08a408f89f758e9a1be629232e3dd055c3a /smcc/src/main/java/at/gv/egiz | |
parent | 83a9b613836910f7edc370c2fe60fa2268dc4461 (diff) | |
download | mocca-b1c8641a63a67e3c64d948f9e8dce5c01e11e2dd.tar.gz mocca-b1c8641a63a67e3c64d948f9e8dce5c01e11e2dd.tar.bz2 mocca-b1c8641a63a67e3c64d948f9e8dce5c01e11e2dd.zip |
Merged feature branch mocca-1.2.13-id@r724 back to trunk.
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@725 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
Diffstat (limited to 'smcc/src/main/java/at/gv/egiz')
26 files changed, 1449 insertions, 761 deletions
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java index 9b3b88ed..e35aa5a4 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -26,7 +26,6 @@ import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import java.util.List; import javax.crypto.Cipher; import javax.crypto.SecretKey; @@ -40,8 +39,8 @@ import javax.smartcardio.CardTerminal; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.util.ISO7816Utils; import at.gv.egiz.smcc.util.SMCCHelper; @@ -49,7 +48,7 @@ import at.gv.egiz.smcc.util.TransparentFileInputStream; public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureCard { - private static Log log = LogFactory.getLog(ACOSCard.class); + private final Logger log = LoggerFactory.getLogger(ACOSCard.class); public static final byte[] AID_DEC = new byte[] { (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x4E }; @@ -115,22 +114,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC (byte) 0x01 // RSA // TODO: Not verified yet }; - private static final PINSpec DEC_PIN_SPEC = new PINSpec(0, 8, "[0-9]", - "at/gv/egiz/smcc/ACOSCard", "dec.pin", KID_PIN_DEC, AID_DEC); - - private static final PINSpec SIG_PIN_SPEC = new PINSpec(0, 8, "[0-9]", - "at/gv/egiz/smcc/ACOSCard", "sig.pin", KID_PIN_SIG, AID_SIG); - - private static final PINSpec INF_PIN_SPEC = new PINSpec(0, 8, "[0-9]", - "at/gv/egiz/smcc/ACOSCard", "inf.pin", KID_PIN_INF, AID_DEC); - - static { - if (SignatureCardFactory.ENFORCE_RECOMMENDED_PIN_LENGTH) { - DEC_PIN_SPEC.setRecLength(4); - SIG_PIN_SPEC.setRecLength(6); - INF_PIN_SPEC.setRecLength(4); - } - } + protected PinInfo decPinInfo, sigPinInfo, infPinInfo; /** * The version of the card's digital signature application. @@ -160,20 +144,29 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC appVersion = 1; log.info("a-sign premium application version = " + appVersion); } catch (SignatureCardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); appVersion = 0; } catch (IOException e) { - log.warn(e); + log.warn("Failed to execute command.", e); appVersion = 0; } catch (CardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); appVersion = 0; - } - - pinSpecs.add(DEC_PIN_SPEC); - pinSpecs.add(SIG_PIN_SPEC); - if (appVersion < 2) { - pinSpecs.add(INF_PIN_SPEC); + } + + 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); } } @@ -205,7 +198,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC int maxSize = -1; if (getAppVersion() < 2) { maxSize = ISO7816Utils.getLengthFromFCx(fcx); - log.debug("Size of selected file = " + maxSize); + log.debug("Size of selected file = {}.", maxSize); } // READ BINARY byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, maxSize, (byte) 0x30); @@ -251,13 +244,13 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC // SELECT file byte[] fcx = execSELECT_FID(channel, EF_INFOBOX); int maxSize = ISO7816Utils.getLengthFromFCx(fcx); - log.debug("Size of selected file = " + maxSize); + log.debug("Size of selected file = {}.", maxSize); // READ BINARY while(true) { try { return ISO7816Utils.readTransparentFileTLV(channel, maxSize, (byte) 0x30); } catch (SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, INF_PIN_SPEC, provider); + verifyPINLoop(channel, infPinInfo, provider); } } @@ -295,7 +288,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC b = is.read(); if (b != 0x01) { - String msg = "Infobox structure v" + b + " not supported."; + String msg = "Infobox structure v{}" + b + " not supported."; log.info(msg); throw new SignatureCardException(msg); } @@ -348,7 +341,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC plainKey = execPSO_DECIPHER(channel, key); break; } catch(SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, DEC_PIN_SPEC, provider); + verifyPINLoop(channel, decPinInfo, provider); } } @@ -444,14 +437,12 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { - PINSpec spec = SIG_PIN_SPEC; - // SELECT application execSELECT_AID(channel, AID_SIG); // MANAGE SECURITY ENVIRONMENT : SET DST execMSE(channel, 0x41, 0xb6, dst.toByteArray()); // VERIFY - verifyPINLoop(channel, spec, provider); + verifyPINLoop(channel, sigPinInfo, provider); // PERFORM SECURITY OPERATION : HASH execPSO_HASH(channel, digest); // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATRE @@ -459,8 +450,6 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { - PINSpec spec = DEC_PIN_SPEC; - // SELECT application execSELECT_AID(channel, AID_DEC); // MANAGE SECURITY ENVIRONMENT : SET AT @@ -471,7 +460,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC // INTERNAL AUTHENTICATE return execINTERNAL_AUTHENTICATE(channel, digest); } catch (SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, spec, provider); + verifyPINLoop(channel, decPinInfo, provider); } } @@ -481,7 +470,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } } catch (CardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); throw new SignatureCardException("Failed to access card.", e); } @@ -492,10 +481,10 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } /* (non-Javadoc) - * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider) + * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.pinInfo, at.gv.egiz.smcc.PINProvider) */ @Override - public void verifyPIN(PINSpec pinSpec, PINGUI pinProvider) + public void verifyPIN(PinInfo pinInfo, PINGUI pinProvider) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { @@ -503,9 +492,9 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC try { // SELECT application - execSELECT_AID(channel, pinSpec.getContextAID()); + execSELECT_AID(channel, pinInfo.getContextAID()); // VERIFY - verifyPINLoop(channel, pinSpec, pinProvider); + verifyPINLoop(channel, pinInfo, pinProvider); } catch (CardException e) { log.info("Failed to verify PIN.", e); throw new SignatureCardException("Failed to verify PIN.", e); @@ -514,10 +503,10 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } /* (non-Javadoc) - * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.ChangePINProvider) + * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.pinInfo, at.gv.egiz.smcc.ChangePINProvider) */ @Override - public void changePIN(PINSpec pinSpec, ModifyPINGUI pinProvider) + public void changePIN(PinInfo pinInfo, ModifyPINGUI pinProvider) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { @@ -525,9 +514,9 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC try { // SELECT application - execSELECT_AID(channel, pinSpec.getContextAID()); + execSELECT_AID(channel, pinInfo.getContextAID()); // CHANGE REFERENCE DATA - changePINLoop(channel, pinSpec, pinProvider); + changePINLoop(channel, pinInfo, pinProvider); } catch (CardException e) { log.info("Failed to change PIN.", e); throw new SignatureCardException("Failed to change PIN.", e); @@ -536,7 +525,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } @Override - public void activatePIN(PINSpec pinSpec, ModifyPINGUI pinGUI) + public void activatePIN(PinInfo pinInfo, ModifyPINGUI pinGUI) throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException { log.error("ACTIVATE PIN not supported by ACOS"); @@ -544,29 +533,20 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } @Override - public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pinGUI) + 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#getPINSpecs() + * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getpinInfos() */ @Override - public List<PINSpec> getPINSpecs() { - if (getAppVersion() < 2) { - return Arrays.asList(new PINSpec[] {DEC_PIN_SPEC, SIG_PIN_SPEC, INF_PIN_SPEC}); - } else { - return Arrays.asList(new PINSpec[] {DEC_PIN_SPEC, SIG_PIN_SPEC}); + public PinInfo[] getPinInfos() { + if (appVersion < 2) { + return new PinInfo[] {decPinInfo, sigPinInfo, infPinInfo }; } - } - - /* (non-Javadoc) - * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPINStatus(at.gv.egiz.smcc.PINSpec) - */ - @Override - public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException { - return PIN_STATE.UNKNOWN; + return new PinInfo[] {decPinInfo, sigPinInfo }; } @Override @@ -578,7 +558,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC // PROTECTED METHODS (assume exclusive card access) //////////////////////////////////////////////////////////////////////// - protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINGUI provider) + protected void verifyPINLoop(CardChannel channel, PinInfo spec, PINGUI provider) throws InterruptedException, CardException, SignatureCardException { int retries = -1; @@ -587,7 +567,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } while (retries > 0); } - protected void changePINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider) + protected void changePINLoop(CardChannel channel, PinInfo spec, ModifyPINGUI provider) throws InterruptedException, CardException, SignatureCardException { int retries = -1; @@ -596,44 +576,48 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } while (retries > 0); } - protected int verifyPIN(CardChannel channel, PINSpec pinSpec, + 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, pinSpec.getKID(), (byte) 0x08, + (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, pinSpec, retries); + 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, PINSpec pinSpec, + 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, pinSpec.getKID(), (byte) 0x10, + (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, @@ -643,23 +627,27 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC - ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinSpec, retries); + 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); } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java index fcb94fc6..73dadceb 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -18,8 +18,6 @@ package at.gv.egiz.smcc; import at.gv.egiz.smcc.reader.CardReader; import at.gv.egiz.smcc.reader.ReaderFactory; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import java.util.ResourceBundle; @@ -28,14 +26,12 @@ import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class AbstractSignatureCard implements SignatureCard { - private static Log log = LogFactory.getLog(AbstractSignatureCard.class); - - protected List<PINSpec> pinSpecs = new ArrayList<PINSpec>(); + private final Logger log = LoggerFactory.getLogger(AbstractSignatureCard.class); private ResourceBundle i18n; private String resourceBundleName; @@ -118,4 +114,16 @@ public abstract class AbstractSignatureCard implements SignatureCard { } } + public void interfaceMethod(PinInfoTest pinInfo) { + + } + + int testMember = 3; + + public static class PinInfoTest { + + void setStatus(int status) { + } + + } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java b/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java index 41358bb5..bd42f47c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java @@ -29,8 +29,8 @@ import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.util.ISO7816Utils; import at.gv.egiz.smcc.util.SMCCHelper; @@ -40,7 +40,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { /** * Logging facility. */ - private static Log log = LogFactory.getLog(BELPICCard.class); + private final Logger log = LoggerFactory.getLogger(BELPICCard.class); public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 }; @@ -64,16 +64,15 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { public static final int PINSPEC_SS = 0; - private static final PINSpec SS_PIN_SPEC = - new PINSpec(4, 12, "[0-9]", - "at/gv/egiz/smcc/BELPICCard", "sig.pin", KID, DF_BELPIC); + protected PinInfo ssPinInfo = + new PinInfo(4, 12, "[0-9]", + "at/gv/egiz/smcc/BELPICCard", "sig.pin", KID, DF_BELPIC, PinInfo.UNKNOWN_RETRIES); /** * Creates a new instance. */ public BELPICCard() { super("at/gv/egiz/smcc/BelpicCard"); - pinSpecs.add(SS_PIN_SPEC); } @Override @@ -161,12 +160,12 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { // VERIFY execMSE(channel, 0x41, 0xb6, dst); // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE - verifyPINLoop(channel, SS_PIN_SPEC, provider); + verifyPINLoop(channel, ssPinInfo, provider); // MANAGE SECURITY ENVIRONMENT : SET DST return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel, digest); } catch (CardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); throw new SignatureCardException("Failed to access card.", e); } @@ -176,7 +175,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { return "Belpic Card"; } - protected void verifyPINLoop(CardChannel channel, PINSpec spec, + protected void verifyPINLoop(CardChannel channel, PinInfo spec, PINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { @@ -186,7 +185,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { } while (retries > 0); } - protected int verifyPIN(CardChannel channel, PINSpec pinSpec, + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, PINGUI provider, int retries) throws SignatureCardException, LockedException, NotActivatedException, InterruptedException, CardException { @@ -281,4 +280,4 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { -}
\ No newline at end of file +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java b/smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java new file mode 100644 index 00000000..93c439a3 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java @@ -0,0 +1,280 @@ +/* +* Copyright 2009 Federal Chancellery Austria and +* Graz University of Technology +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.SMCCHelper; + +public class EstEIDCard extends AbstractSignatureCard { + + private final Logger log = LoggerFactory.getLogger(EstEIDCard.class); + + public static final byte KID_PIN_2 = (byte) 0x02; + + public static final byte[] DF = { (byte) 0xEE, (byte) 0xEE }; + + public static final byte[] EF_CERT = { (byte) 0xDD, (byte) 0x0CE }; + + private static final PinInfo QS_PIN_SPEC = new PinInfo(5, 12, "[0-9]", + "at/gv/egiz/smcc/EstEIDCard", "qs.pin", KID_PIN_2, DF, PinInfo.UNKNOWN_RETRIES); + + public EstEIDCard() { + super("at/gv/egiz/smcc/EstEIDCard"); + } + + @Override + public byte[] getCertificate(KeyboxName keyboxName) + throws SignatureCardException, InterruptedException { + + try { + CardChannel channel = getCardChannel(); + // SELECT MF + execSELECT_MF(channel); + // SELECT DF + execSELECT_DF(channel, DF); + // SELECT EF CERT + execSELECT_EF(channel, EF_CERT); + // READ BINARY + byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, -1, (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 + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + if (!"http://www.w3.org/2000/09/xmldsig#rsa-sha1".equals(alg)) { + throw new SignatureCardException("Card does not support algorithm " + alg + "."); + } + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + 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(); + + // SELECT MF + execSELECT_MF(channel); + // SELECT DF + execSELECT_DF(channel, DF); + // MANAGE SECURITY ENVIRONMENT : RESTORE + execMSE(channel, 0xF3, 0x01, null); + // VERIFY + verifyPINLoop(channel, QS_PIN_SPEC, pinGUI); + // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE + return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel, digest); + + } catch (CardException e) { + log.warn("Failed to execute command.", e); + throw new SignatureCardException("Failed to access card.", e); + } + + } + + @Override + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider) throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + int retries = -1; + do { + retries = verifyPIN(channel, spec, provider, retries); + } while (retries >= -1); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries) throws SignatureCardException, + LockedException, NotActivatedException, InterruptedException, + CardException { + + VerifyAPDUSpec apduSpec = new VerifyAPDUSpec( + new byte[] { + (byte) 0x00, (byte) 0x20, (byte) 0x00, pinSpec.getKID()}, + 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 0); + + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); + + if (resp.getSW() == 0x9000) { + return -2; + } + if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } + + switch (resp.getSW()) { + case 0x6300: + // incorrect PIN, number of retries not provided + return -1; + case 0x6400: + // ? + throw new TimeoutException(); + case 0x6983: + // authentication method blocked + throw new LockedException(); + case 0x6984: + // reference data not usable + throw new NotActivatedException(); + case 0x6985: + // conditions of use not satisfied + throw new NotActivatedException(); + + default: + String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW()); + log.info(msg); + throw new SignatureCardException(msg); + } + + } + + + protected void execSELECT_MF(CardChannel channel) + throws SignatureCardException, CardException { + execSELECT(channel, 0x00, null); + } + + protected void execSELECT_DF(CardChannel channel, byte[] fid) + throws SignatureCardException, CardException { + execSELECT(channel, 0x01, fid); + } + + protected void execSELECT_EF(CardChannel channel, byte[] fid) + throws SignatureCardException, CardException { + execSELECT(channel, 0x02, fid); + } + + protected void execSELECT(CardChannel channel, int p1, byte[] fid) + throws SignatureCardException, CardException { + + CommandAPDU command; + if (fid != null) { + command = new CommandAPDU(0x00, 0xA4, p1, 0x0C, fid, 256); + } else { + command = new CommandAPDU(0x00, 0xA4, p1, 0x0C, 256); + } + + ResponseAPDU resp = channel.transmit(command); + + 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); + } + + } + + protected void execMSE(CardChannel channel, int p1, int p2, byte[] data) + throws CardException, SignatureCardException { + + ResponseAPDU resp; + if (data == null) { + resp = channel.transmit(new CommandAPDU(0x00, 0x22, p1, p2)); + } else { + resp = channel.transmit(new CommandAPDU(0x00, 0x22, p1, p2, data)); + } + + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("MSE:SET failed: SW=" + + Integer.toHexString(resp.getSW())); + } + + } + + protected byte[] execPSO_COMPUTE_DIGITAL_SIGNATURE(CardChannel channel, + byte[] hash) throws CardException, SignatureCardException { + + byte[] oid = 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) 0x14 }; + + ByteArrayOutputStream data = new ByteArrayOutputStream(); + + try { + // oid + data.write(oid); + // hash + data.write(hash); + } catch (IOException e) { + throw new SignatureCardException(e); + } + + ResponseAPDU resp = channel + .transmit(new CommandAPDU(0x00, 0x2A, 0x9E, 0x9A, data.toByteArray(), 0x80)); + + if (resp.getSW() != 0x9000) { + throw new SignatureCardException( + "PSO: COMPUTE DIGITAL SIGNATRE failed: SW=" + + Integer.toHexString(resp.getSW())); + } else { + return resp.getData(); + } + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java b/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java index bfbd0063..2562ae56 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java @@ -26,12 +26,12 @@ import javax.smartcardio.Card; import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ExclSignatureCardProxy implements InvocationHandler { - private static Log log = LogFactory.getLog(ExclSignatureCardProxy.class); + private final Logger log = LoggerFactory.getLogger(ExclSignatureCardProxy.class); private static final Method init; @@ -85,11 +85,10 @@ public class ExclSignatureCardProxy implements InvocationHandler { if (card != null) { try { - log.trace("Invoking method " + method.getName() + "() with exclusive access."); + log.trace("Invoking method {}() with exclusive access.", method.getName()); card.beginExclusive(); } catch (CardException e) { - log.info("Failed to get exclusive access to signature card " - + signatureCard.toString() + "."); + log.info("Failed to get exclusive access to signature card {}.", signatureCard); throw new SignatureCardException(e); } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java index 64389190..9ed65d53 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java @@ -29,8 +29,8 @@ import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.util.ISO7816Utils; import at.gv.egiz.smcc.util.SMCCHelper; @@ -40,7 +40,7 @@ public class ITCard extends AbstractSignatureCard { /** * Logging facility. */ - private static Log log = LogFactory.getLog(STARCOSCard.class); + private final Logger log = LoggerFactory.getLogger(STARCOSCard.class); public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 }; @@ -48,17 +48,15 @@ public class ITCard extends AbstractSignatureCard { public static final byte[] EF_C_Carta = new byte[] { (byte) 0x11, (byte) 0x01 }; - private static final PINSpec SS_PIN_SPEC = - new PINSpec(5, 8, "[0-9]", - "at/gv/egiz/smcc/ITCard", "sig.pin", (byte) 0x10, - new byte[] { (byte) 0x11, (byte) 0x00 }); - + protected PinInfo ssPinInfo = new PinInfo(5, 8, "[0-9]", + "at/gv/egiz/smcc/ITCard", "sig.pin", (byte) 0x10, + new byte[] { (byte) 0x11, (byte) 0x00 }, PinInfo.UNKNOWN_RETRIES); + /** * Creates a new instance. */ public ITCard() { super("at/gv/egiz/smcc/ITCard"); - pinSpecs.add(SS_PIN_SPEC); } @Override @@ -144,7 +142,7 @@ public class ITCard extends AbstractSignatureCard { // SELECT MF execSELECT_FID(channel, MF); // VERIFY - verifyPINLoop(channel, SS_PIN_SPEC, provider); + verifyPINLoop(channel, ssPinInfo, provider); // MANAGE SECURITY ENVIRONMENT : RESTORE SE execMSE(channel, 0xF3, 0x03, null); // MANAGE SECURITY ENVIRONMENT : SET DST @@ -153,13 +151,13 @@ public class ITCard extends AbstractSignatureCard { return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel, digest); } catch (CardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); throw new SignatureCardException("Failed to access card.", e); } } - protected void verifyPINLoop(CardChannel channel, PINSpec spec, + protected void verifyPINLoop(CardChannel channel, PinInfo spec, PINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { @@ -169,7 +167,7 @@ public class ITCard extends AbstractSignatureCard { } while (retries >= -1); } - protected int verifyPIN(CardChannel channel, PINSpec pinSpec, + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, PINGUI provider, int retries) throws SignatureCardException, LockedException, NotActivatedException, InterruptedException, CardException { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java index 3fc80fa1..cbccda3d 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java @@ -24,12 +24,12 @@ import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class LogCardChannel extends CardChannel { - protected static Log log = LogFactory.getLog(LogCardChannel.class); + private final Logger log = LoggerFactory.getLogger(LogCardChannel.class); private CardChannel channel; @@ -61,11 +61,11 @@ public class LogCardChannel extends CardChannel { switch (command.getINS()) { case 0x20: // VERIFY case 0x21: // VERIFY - case 0x24: { // CHANGE REFERENCE DATA - // Don't log possibly sensitive command data + case 0x24: { // CHANGE REFERENCE DATA + // Don't log possibly sensitive command data StringBuilder sb = new StringBuilder(); sb.append(command); - sb.append('\n'); + sb.append("\n-> "); byte[] c = new byte[4]; c[0] = (byte) command.getCLA(); c[1] = (byte) command.getINS(); @@ -87,12 +87,12 @@ public class LogCardChannel extends CardChannel { }; break; default: - log.trace(command + "\n" + toString(command.getBytes())); + log.trace(command + "\n-> " + toString(command.getBytes())); } long t0 = System.currentTimeMillis(); ResponseAPDU response = channel.transmit(command); long t1 = System.currentTimeMillis(); - log.trace(response + " [" + (t1 - t0) + "ms]\n" + toString(response.getBytes())); + log.trace(response + " [" + (t1 - t0) + "ms]\n<- " + toString(response.getBytes())); return response; } else { return channel.transmit(command); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java index 24dfa53c..4d7d34f5 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java @@ -23,4 +23,7 @@ package at.gv.egiz.smcc; * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> */ public class PINConfirmationException extends SignatureCardException { + + private static final long serialVersionUID = 1L; + } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java index 721c63e2..08bc0f18 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java @@ -23,4 +23,7 @@ package at.gv.egiz.smcc; * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> */ public class PINFormatException extends SignatureCardException { + + private static final long serialVersionUID = 1L; + } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java index 5091c10f..70b19ff0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java @@ -19,26 +19,26 @@ package at.gv.egiz.smcc; import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; import at.gv.egiz.smcc.pin.gui.PINGUI; -import java.util.List; public interface PINMgmtSignatureCard extends SignatureCard { - public enum PIN_STATE {UNKNOWN, ACTIV, NOT_ACTIV, BLOCKED}; - - public List<PINSpec> getPINSpecs(); + /** + * PinInfo declares protected methods to be used from within card implementations. + * DO NOT REFACTOR CARD INTERFACE AND IMPLEMENTATIONS TO SEPARATE PACKAGES + * @throws SignatureCardException if the card is STARCOS G3 and not activated (G3 pin activation fails if card not active) + */ + public PinInfo[] getPinInfos() throws SignatureCardException; - public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException; - - public void verifyPIN(PINSpec pinSpec, PINGUI pinGUI) + public void verifyPIN(PinInfo pinInfo, PINGUI pinGUI) throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException; - public void changePIN(PINSpec pinSpec, ModifyPINGUI changePINGUI) + public void changePIN(PinInfo pinInfo, ModifyPINGUI changePINGUI) throws LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException; - public void activatePIN(PINSpec pinSpec, ModifyPINGUI activatePINGUI) + public void activatePIN(PinInfo pinInfo, ModifyPINGUI activatePINGUI) throws CancelledException, SignatureCardException, InterruptedException; - public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pukGUI) + public void unblockPIN(PinInfo pinInfo, ModifyPINGUI pukGUI) throws CancelledException, SignatureCardException, InterruptedException; } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/PinInfo.java index f68edbed..d2acf666 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PinInfo.java @@ -24,18 +24,25 @@ import java.util.ResourceBundle; * * @author mcentner */ -public class PINSpec { +public class PinInfo { + public enum STATE {UNKNOWN, ACTIV, NOT_ACTIV, BLOCKED}; + + /** + * the number of remaining retries is unknown or irrelevant (blocked, not active states) + */ + public static final int UNKNOWN_RETRIES = -1; + /** * The minimum PIN length. */ - protected int minLength = 0; + protected final int minLength; /** * The maximum PIN length or -1 if not specified. */ - protected int maxLength = -1; - + protected final int maxLength; + /** * The recommended PIN length or -1 if not specified. */ @@ -44,34 +51,42 @@ public class PINSpec { /** * The regular expression pattern of a single PIN digit or character. */ - protected String rexepPattern; + protected final String rexepPattern; /** * The name of the corresponding resource bundle. */ - protected String resourceBundleName; + protected final String resourceBundleName; /** * The key of the PIN name in the resource bundle. */ - protected String nameKey; + protected final String nameKey; /** - * The name of the PIN. - */ - protected String name; - - /** * The key id to be used in VERIFY or CHANGE REFERENCE DATA APDUs. */ - protected byte kid; + protected final byte kid; /** * The context AID of the key id. */ - protected byte[] context_aid; + protected final byte[] context_aid; + + protected final int maxRetries; + + /** + * The current status of this PIN + */ + protected STATE state = STATE.UNKNOWN; /** + * number of further allowed retries (before the pin is blocked) + */ + protected int retries = UNKNOWN_RETRIES; + + + /** * Creates a new instance of this PINSpec with the given lengths, regular * expression pattern, the ResourceBundle name and key to lookup the PIN name * and the KID and AID. @@ -84,8 +99,8 @@ public class PINSpec { * @param kid the key id of the PIN * @param contextAID the AID the KID is valid in */ - public PINSpec(int minLenght, int maxLength, String rexepPattern, - String resourceBundleName, String resourceKey, byte kid, byte[] contextAID) { + public PinInfo(int minLenght, int maxLength, String rexepPattern, + String resourceBundleName, String resourceKey, byte kid, byte[] contextAID, int maxRetries) { this.minLength = minLenght; this.maxLength = maxLength; @@ -94,48 +109,23 @@ public class PINSpec { this.nameKey = resourceKey + ".name"; this.kid = kid; this.context_aid = contextAID; - } - - /** - * Creates a new instance of this PINSpec with the given lengths, regular - * expression pattern, the name of the PIN and the KID and AID. - * - * @param minLenght the minimum length of the PIN - * @param maxLength the maximum length of the PIN, or -1 if there is no maximum length - * @param rexepPattern the regular expression pattern of a single PIN digit or character - * @param name the name of the PIN - * @param kid the key id of the PIN - * @param contextAID the AID the KID is valid in - */ - public PINSpec(int minLenght, int maxLength, String rexepPattern, - String name, byte kid, byte[] contextAID) { - - this.minLength = minLenght; - this.maxLength = maxLength; - this.rexepPattern = rexepPattern; - this.name = name; - this.kid = kid; - this.context_aid = contextAID; + this.maxRetries = maxRetries; } /** * This method sets the recommended PIN length. - * + * * @param recLength the recommended PIN length */ public void setRecLength(int recLength) { this.recLength = recLength; } - + /** - * @return the localized (using the default locale) name of the PIN, or the - * name set by - * {@link #PINSpec(int, int, String, String, byte, byte[])}. + * @return the localized (using the default locale) name of the PIN */ public String getLocalizedName() { - if (name != null) { - return name; - } else if (resourceBundleName != null){ + if (resourceBundleName != null){ try { return ResourceBundle.getBundle(resourceBundleName).getString(nameKey); } catch (MissingResourceException e) { @@ -146,13 +136,10 @@ public class PINSpec { /** * @param locale the locale for which the name should be returned - * @return the localized name of the PIN, or the name set by - * {@link #PINSpec(int, int, String, String, byte, byte[])} + * @return the localized name of the PIN, */ public String getLocalizedName(Locale locale) { - if (name != null) { - return name; - } else if (resourceBundleName != null) { + if (resourceBundleName != null) { try { return ResourceBundle.getBundle(resourceBundleName, locale).getString(nameKey); } catch (MissingResourceException e) { @@ -235,5 +222,37 @@ public class PINSpec { public byte[] getContextAID() { return context_aid; } - + + public STATE getState() { + return state; + } + + public int getRetries() { + return retries; + } + + ////////////////////////////////////////////////////////////////////////////// + //* PinInfo declares protected methods to be used from within card implementations. + //* DO NOT REFACTOR CARD INTERFACE AND IMPLEMENTATIONS TO SEPARATE PACKAGES + + protected void setNotActive() { + this.state = STATE.NOT_ACTIV; + this.retries = UNKNOWN_RETRIES; + } + + protected void setActive(int retries) { + this.state = STATE.ACTIV; + this.retries = retries; + } + + protected void setBlocked() { + this.state = STATE.BLOCKED; + this.retries = UNKNOWN_RETRIES; + } + + protected void setUnknown() { + this.state = STATE.UNKNOWN; + this.retries = UNKNOWN_RETRIES; + } + } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java b/smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java new file mode 100644 index 00000000..8bd49e01 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java @@ -0,0 +1,310 @@ +/* + * Copyright 2010 Federal Chancellery Austria and + * Graz University of Technology + * + * based on an implementation + * + * Copyright 2009 Manuel Preliteiro, MULTICERT S.A. + * + * 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://ec.europa.eu/idabc/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. + */ + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.SMCCHelper; + +public class PtEidCard extends AbstractSignatureCard { + + private final Logger log = LoggerFactory.getLogger(PtEidCard.class); + + private static final byte[] AID_APPLET = { (byte) 0x60, (byte) 0x46, (byte) 0x32, + (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x02 }; + + private static final byte[] DF_ISSUES = {(byte) 0x5F, (byte) 0x00}; + + private static final byte[] EF_SIGN_CERT = { (byte) 0xEF, (byte) 0x08 }; + + private static final PinInfo QS_PIN_SPEC = + new PinInfo(4, 4, "[0-9]", + "at/gv/egiz/smcc/PtEidCard", "sig.pin", (byte) 0x82, DF_ISSUES, PinInfo.UNKNOWN_RETRIES); + + protected PtEidCard() { + super("at/gv/egiz/smcc/PtEidCard"); + } + + @Override + public byte[] getCertificate(KeyboxName keyboxName) + throws SignatureCardException, InterruptedException { + + try { + CardChannel channel = getCardChannel(); + // SELECT applet + execSELECT_AID(channel, AID_APPLET); + // SELECT DF_ISSUES + execSELECT_FID(channel, DF_ISSUES); + // SELECT EF_SIGN_CERT + byte[] fcx = execSELECT_FID(channel, EF_SIGN_CERT); + int maxsize = ISO7816Utils.getLengthFromFCx(fcx); + // 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 + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + @Override + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + if (!"http://www.w3.org/2000/09/xmldsig#rsa-sha1".equals(alg)) { + throw new SignatureCardException("Card does not support algorithm " + alg + "."); + } + + final byte[] dst = { + (byte) 0x80, // algorithm reference + (byte) 0x01, (byte) 0x12, // RSASSA-PKCS1-v1.5 using SHA1 + (byte) 0x84, // private key reference + (byte) 0x01, (byte) 0x01}; + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + 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(); + + // SELECT applet + execSELECT_AID(channel, AID_APPLET); + // SELECT DF_ISSUES + execSELECT_FID(channel, DF_ISSUES); + // VERIFY + verifyPINLoop(channel, QS_PIN_SPEC, pinGUI); + // MANAGE SECURITY ENVIRONMENT : RESTORE SE + execMSE(channel, 0x73, 0x03, null); + // MANAGE SECURITY ENVIRONMENT : SET DST + execMSE(channel, 0x41, 0xB6, dst); + // PERFORM SECURITY OPERATION : HASH + execPSO_HASH(channel, digest); + // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE + return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel); + + } catch (CardException e) { + log.warn("Failed to execute command.", e); + throw new SignatureCardException("Failed to access card.", e); + } + + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider) throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + int retries = -1; + do { + retries = verifyPIN(channel, spec, provider, retries); + } while (retries >= -1); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries) throws SignatureCardException, + LockedException, NotActivatedException, InterruptedException, + CardException { + + VerifyAPDUSpec apduSpec = new VerifyAPDUSpec( + new byte[] { (byte) 0x00, (byte) 0x20, (byte) 0x00, pinSpec.getKID(), + (byte) 0x08, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF }, + 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8); + + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); + + if (resp.getSW() == 0x9000) { + return -2; + } + if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } + + switch (resp.getSW()) { + case 0x6300: + // incorrect PIN, number of retries not provided + return -1; + case 0x6983: + // authentication method blocked + throw new LockedException(); + + default: + String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW()); + log.info(msg); + throw new SignatureCardException(msg); + } + + } + + + + protected void execSELECT_AID(CardChannel channel, byte[] aid) + throws SignatureCardException, CardException { + + ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x04, + 0x0C, aid, 256)); + + if (resp.getSW() == 0x6A82) { + String msg = "File or application not found FID=" + + 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 FID=" + + SMCCHelper.toString(aid) + " SW=" + + Integer.toHexString(resp.getSW()) + "."; + log.error(msg); + throw new SignatureCardException(msg); + } + + } + + 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(); + } + + } + + protected void execMSE(CardChannel channel, int p1, int p2, byte[] data) + throws CardException, SignatureCardException { + + ResponseAPDU resp; + if (data == null) { + resp = channel.transmit(new CommandAPDU(0x00, 0x22, p1, p2, 256)); + } else { + resp = channel.transmit(new CommandAPDU(0x00, 0x22, p1, p2, data, 256)); + } + + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("MSE:SET failed: SW=" + + Integer.toHexString(resp.getSW())); + } + } + + protected void execPSO_HASH(CardChannel channel, byte[] hash) throws CardException, SignatureCardException { + + ByteArrayOutputStream data = new ByteArrayOutputStream(hash.length + 2); + try { + data.write(0x90); + data.write(hash.length); + data.write(hash); + } catch (IOException e) { + throw new SignatureCardException(e); + } + + ResponseAPDU resp = channel.transmit( + new CommandAPDU(0x00, 0x2A, 0x90, 0xA0, data.toByteArray())); + 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, 0x14)); + + if (resp.getSW() == 0x6982) { + throw new SecurityStatusNotSatisfiedException(); + } else if (resp.getSW() == 0x6983) { + throw new LockedException(); + } else if (resp.getSW() != 0x9000) { + throw new SignatureCardException( + "PSO: COMPUTE DIGITAL SIGNATRE failed: SW=" + + Integer.toHexString(resp.getSW())); + } else { + return resp.getData(); + } + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java index b876847f..8de4eeb8 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -24,8 +24,6 @@ import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.List; import javax.smartcardio.Card; import javax.smartcardio.CardChannel; @@ -34,8 +32,8 @@ import javax.smartcardio.CardTerminal; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.util.ISO7816Utils; import at.gv.egiz.smcc.util.SMCCHelper; @@ -45,7 +43,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu /** * Logging facility. */ - private static Log log = LogFactory.getLog(STARCOSCard.class); + private final Logger log = LoggerFactory.getLogger(STARCOSCard.class); public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 }; @@ -131,30 +129,16 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu public static final byte KID_PIN_CARD = (byte) 0x01; - private static final PINSpec CARD_PIN_SPEC = - new PINSpec(4, 12, "[0-9]", - "at/gv/egiz/smcc/STARCOSCard", "card.pin", KID_PIN_CARD, null); - - private static final PINSpec SS_PIN_SPEC = - new PINSpec(6, 12, "[0-9]", - "at/gv/egiz/smcc/STARCOSCard", "sig.pin", KID_PIN_SS, AID_DF_SS); - - static { - if (SignatureCardFactory.ENFORCE_RECOMMENDED_PIN_LENGTH) { - CARD_PIN_SPEC.setRecLength(4); - SS_PIN_SPEC.setRecLength(6); - } - } - protected double version = 1.1; + protected PinInfo cardPinInfo; + protected PinInfo ssPinInfo; + /** * Creates a new instance. */ public STARCOSCard() { super("at/gv/egiz/smcc/STARCOSCard"); - pinSpecs.add(CARD_PIN_SPEC); - pinSpecs.add(SS_PIN_SPEC); } /* (non-Javadoc) @@ -163,7 +147,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu @Override public void init(Card card, CardTerminal cardTerminal) { super.init(card, cardTerminal); - + // determine application version CardChannel channel = getCardChannel(); try { @@ -179,17 +163,27 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu log.info("e-card version=" + version + " (" + generation + ")"); } } catch (CardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); } catch (SignatureCardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); + } + + cardPinInfo = new PinInfo(4, 12, "[0-9]", + "at/gv/egiz/smcc/STARCOSCard", "card.pin", KID_PIN_CARD, null, 10); + ssPinInfo = new PinInfo(6, 12, "[0-9]", + "at/gv/egiz/smcc/STARCOSCard", "sig.pin", KID_PIN_SS, AID_DF_SS, + (version < 1.2) ? 3 : 10); + + if (SignatureCardFactory.ENFORCE_RECOMMENDED_PIN_LENGTH) { + cardPinInfo.setRecLength(4); + ssPinInfo.setRecLength(6); } - } @Override @Exclusive public byte[] getCertificate(KeyboxName keyboxName) - throws SignatureCardException, InterruptedException { + throws SignatureCardException { byte[] aid; byte[] fid; @@ -233,8 +227,6 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu try { if ("IdentityLink".equals(infobox)) { - PINSpec spec = CARD_PIN_SPEC; - CardChannel channel = getCardChannel(); // SELECT application execSELECT_AID(channel, AID_INFOBOX); @@ -245,7 +237,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu try { return ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30); } catch (SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, spec, pinGUI); + verifyPINLoop(channel, cardPinInfo, pinGUI); } } @@ -295,7 +287,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } } catch (CardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); throw new SignatureCardException("Failed to access card.", e); } } @@ -368,14 +360,12 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { - PINSpec spec = SS_PIN_SPEC; - // SELECT MF execSELECT_MF(channel); // SELECT application execSELECT_AID(channel, AID_DF_SS); // VERIFY - verifyPINLoop(channel, spec, provider); + verifyPINLoop(channel, ssPinInfo, provider); // MANAGE SECURITY ENVIRONMENT : SET DST execMSE(channel, 0x41, 0xb6, dst.toByteArray()); if (version < 1.2) { @@ -395,8 +385,6 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { - PINSpec spec = CARD_PIN_SPEC; - // SELECT application execSELECT_AID(channel, AID_DF_GS); // MANAGE SECURITY ENVIRONMENT : SET DST @@ -412,7 +400,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel, null); } catch (SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, spec, provider); + verifyPINLoop(channel, cardPinInfo, provider); } } @@ -422,29 +410,29 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } } catch (CardException e) { - log.warn(e); + log.warn("Failed to execute command.", e); throw new SignatureCardException("Failed to access card.", e); } } /* (non-Javadoc) - * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider) + * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PinInfo, at.gv.egiz.smcc.PINProvider) */ @Override @Exclusive - public void verifyPIN(PINSpec pinSpec, PINGUI pinProvider) + public void verifyPIN(PinInfo pinInfo, PINGUI pinProvider) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { CardChannel channel = getCardChannel(); try { - if (pinSpec.getContextAID() != null) { + if (pinInfo.getContextAID() != null) { // SELECT application - execSELECT_AID(channel, pinSpec.getContextAID()); + execSELECT_AID(channel, pinInfo.getContextAID()); } - verifyPINLoop(channel, pinSpec, pinProvider); + verifyPINLoop(channel, pinInfo, pinProvider); } catch (CardException e) { log.info("Failed to verify PIN.", e); throw new SignatureCardException("Failed to verify PIN.", e); @@ -453,22 +441,22 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } /* (non-Javadoc) - * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.ChangePINProvider) + * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.PinInfo, at.gv.egiz.smcc.ChangePINProvider) */ @Override @Exclusive - public void changePIN(PINSpec pinSpec, ModifyPINGUI pinGUI) + public void changePIN(PinInfo pinInfo, ModifyPINGUI pinGUI) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { CardChannel channel = getCardChannel(); try { - if (pinSpec.getContextAID() != null) { + if (pinInfo.getContextAID() != null) { // SELECT application - execSELECT_AID(channel, pinSpec.getContextAID()); + execSELECT_AID(channel, pinInfo.getContextAID()); } - changePINLoop(channel, pinSpec, pinGUI); + changePINLoop(channel, pinInfo, pinGUI); } catch (CardException e) { log.info("Failed to change PIN.", e); throw new SignatureCardException("Failed to change PIN.", e); @@ -477,22 +465,22 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } /* (non-Javadoc) - * @see at.gv.egiz.smcc.AbstractSignatureCard#activatePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider) + * @see at.gv.egiz.smcc.AbstractSignatureCard#activatePIN(at.gv.egiz.smcc.PinInfo, at.gv.egiz.smcc.PINProvider) */ @Override @Exclusive - public void activatePIN(PINSpec pinSpec, ModifyPINGUI activatePINGUI) + public void activatePIN(PinInfo pinInfo, ModifyPINGUI activatePINGUI) throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException { CardChannel channel = getCardChannel(); try { - if (pinSpec.getContextAID() != null) { + if (pinInfo.getContextAID() != null) { // SELECT application - execSELECT_AID(channel, pinSpec.getContextAID()); + execSELECT_AID(channel, pinInfo.getContextAID()); } - activatePIN(channel, pinSpec, activatePINGUI); + activatePIN(channel, pinInfo, activatePINGUI); } catch (CardException e) { log.info("Failed to activate PIN.", e); throw new SignatureCardException("Failed to activate PIN.", e); @@ -501,15 +489,15 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } /* (non-Javadoc) - * @see at.gv.egiz.smcc.PINMgmtSignatureCard#unblockPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider) + * @see at.gv.egiz.smcc.PINMgmtSignatureCard#unblockPIN(at.gv.egiz.smcc.PinInfo, at.gv.egiz.smcc.PINProvider) */ @Override - public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pukProvider) + public void unblockPIN(PinInfo pinInfo, ModifyPINGUI pukProvider) throws CancelledException, SignatureCardException, InterruptedException { CardChannel channel = getCardChannel(); try { - unblockPINLoop(channel, pinSpec, pukProvider); + unblockPINLoop(channel, pinInfo, pukProvider); } catch (CardException e) { log.info("Failed to activate PIN.", e); throw new SignatureCardException("Failed to activate PIN.", e); @@ -520,7 +508,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu public void reset() throws SignatureCardException { try { super.reset(); - log.debug("select MF (e-card workaround)"); + log.debug("Select MF (e-card workaround)."); CardChannel channel = getCardChannel(); ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x00, 0x0C)); if (resp.getSW() != 0x9000) { @@ -533,41 +521,39 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } /* (non-Javadoc) - * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPINSpecs() + * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPinInfos() */ @Override - public List<PINSpec> getPINSpecs() { - return Arrays.asList(new PINSpec[] {CARD_PIN_SPEC, SS_PIN_SPEC}); - } + public PinInfo[] getPinInfos() throws SignatureCardException { + + if (version >= 1.2) { + //check if card is activated + getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR); + } + + PinInfo[] pinInfos = new PinInfo[] {cardPinInfo, ssPinInfo}; - /* (non-Javadoc) - * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPINStatus(at.gv.egiz.smcc.PINSpec) - */ - @Override - public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException { - CardChannel channel = getCardChannel(); - - try { - if (pinSpec.getContextAID() != null) { - // SELECT AID - execSELECT_AID(channel, pinSpec.getContextAID()); + for (PinInfo pinInfo : pinInfos) { + if (pinInfo.getState() == PinInfo.STATE.UNKNOWN ) { + try { + log.debug("Query pin status for {}.", pinInfo.getLocalizedName()); + if (pinInfo.getContextAID() != null) { + execSELECT_AID(channel, pinInfo.getContextAID()); + } + verifyPIN(channel, pinInfo, null, 0); + } catch (Exception e) { + log.trace("Failed to execute command.", e); + // status already set by verifyPIN + } + } else if (log.isTraceEnabled()) { + log.trace("assume pin status {} to be up to date", pinInfo.getState()); } - verifyPIN(channel, pinSpec, null, 0); - return PIN_STATE.ACTIV; - } catch (InterruptedException e) { - return PIN_STATE.UNKNOWN; - } catch (LockedException e) { - return PIN_STATE.BLOCKED; - } catch (NotActivatedException e) { - return PIN_STATE.NOT_ACTIV; - } catch (CardException e) { - log.error("Failed to get PIN status.", e); - throw new SignatureCardException("Failed to get PIN status.", e); } - + return pinInfos; } + @Override public String toString() { return "e-card"; } @@ -576,110 +562,121 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu // PROTECTED METHODS (assume exclusive card access) //////////////////////////////////////////////////////////////////////// - protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINGUI provider) + protected void verifyPINLoop(CardChannel channel, PinInfo pinInfo, PINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { - int retries = verifyPIN(channel, spec, null, -1); + int retries = verifyPIN(channel, pinInfo, null, -1); do { - retries = verifyPIN(channel, spec, provider, retries); + retries = verifyPIN(channel, pinInfo, provider, retries); } while (retries > 0); } - protected void changePINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider) + protected void changePINLoop(CardChannel channel, PinInfo pinInfo, ModifyPINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { - int retries = verifyPIN(channel, spec, null, -1); + int retries = verifyPIN(channel, pinInfo, null, -1); do { - retries = changePIN(channel, spec, provider, retries); + retries = changePIN(channel, pinInfo, provider, retries); } while (retries > 0); } - protected void unblockPINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider) + protected void unblockPINLoop(CardChannel channel, PinInfo pinInfo, ModifyPINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { //TODO get PUK retry counter from EF FID 0036 in MF int retries = -1; do { - retries = unblockPIN(channel, spec, provider, retries); + retries = unblockPIN(channel, pinInfo, provider, retries); } while (retries > 0); } - protected int verifyPIN(CardChannel channel, PINSpec pinSpec, + protected int verifyPIN(CardChannel channel, PinInfo pinInfo, PINGUI provider, int retries) throws SignatureCardException, LockedException, NotActivatedException, InterruptedException, CardException { VerifyAPDUSpec apduSpec = new VerifyAPDUSpec( new byte[] { - (byte) 0x00, (byte) 0x20, (byte) 0x00, pinSpec.getKID(), (byte) 0x08, + (byte) 0x00, (byte) 0x20, (byte) 0x00, pinInfo.getKID(), (byte) 0x08, (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4); ResponseAPDU resp; if (provider != null) { - resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); + resp = reader.verify(channel, apduSpec, provider, pinInfo, retries); } else { - resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00, pinSpec.getKID())); + resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00, pinInfo.getKID())); } if (resp.getSW() == 0x9000) { + pinInfo.setActive(pinInfo.maxRetries); return -1; } else if (resp.getSW() == 0x6983 || resp.getSW() == 0x63c0) { // authentication method blocked (0x63c0 returned by 'short' VERIFY) + pinInfo.setBlocked(); throw new LockedException(); } else if (resp.getSW() == 0x6984 || resp.getSW() == 0x6985) { // reference data not usable; conditions of use not satisfied + pinInfo.setNotActive(); throw new NotActivatedException(); } else if (resp.getSW() >> 4 == 0x63c) { + pinInfo.setActive(0x0f & resp.getSW()); return 0x0f & resp.getSW(); } else if (version >= 1.2 && resp.getSW() == 0x6400) { String msg = "VERIFY failed, card not activated. SW=0x6400"; log.error(msg); + pinInfo.setNotActive(); throw new SignatureCardException(msg); } else { String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW()); log.error(msg); + pinInfo.setUnknown(); throw new SignatureCardException(msg); } } - protected int changePIN(CardChannel channel, PINSpec pinSpec, + 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, pinSpec.getKID(), (byte) 0x10, + (byte) 0x00, (byte) 0x24, (byte) 0x00, pinInfo.getKID(), (byte) 0x10, (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4, 8); - ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinSpec, retries); + ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinInfo, retries); if (resp.getSW() == 0x9000) { + pinInfo.setActive(pinInfo.maxRetries); return -1; } else if (resp.getSW() == 0x6983) { // authentication method blocked + pinInfo.setBlocked(); throw new LockedException(); } else if (resp.getSW() == 0x6984) { + pinInfo.setNotActive(); throw new NotActivatedException(); } else if (resp.getSW() >> 4 == 0x63c) { + pinInfo.setActive(0x0f & resp.getSW()); return 0x0f & resp.getSW(); } else { String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW()); log.error(msg); + pinInfo.setUnknown(); throw new SignatureCardException(msg); } } - protected int activatePIN(CardChannel channel, PINSpec pinSpec, + protected int activatePIN(CardChannel channel, PinInfo pinInfo, ModifyPINGUI provider) throws SignatureCardException, InterruptedException, CardException { @@ -687,35 +684,37 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu if (version < 1.2) { NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec( new byte[] { - (byte) 0x00, (byte) 0x24, (byte) 0x01, pinSpec.getKID(), (byte) 0x08, + (byte) 0x00, (byte) 0x24, (byte) 0x01, pinInfo.getKID(), (byte) 0x08, (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4); - resp = reader.modify(channel, apduSpec, provider, pinSpec); + resp = reader.modify(channel, apduSpec, provider, pinInfo); } else { NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec( new byte[] { - (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.getKID(), (byte) 0x10, + (byte) 0x00, (byte) 0x24, (byte) 0x00, pinInfo.getKID(), (byte) 0x10, (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4); apduSpec.setPinInsertionOffsetNew(8); - resp = reader.modify(channel, apduSpec, provider, pinSpec); + resp = reader.modify(channel, apduSpec, provider, pinInfo); } if (resp.getSW() == 0x9000) { + pinInfo.setActive(pinInfo.maxRetries); return -1; } else { String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW()); log.error(msg); + pinInfo.setUnknown(); throw new SignatureCardException(msg); } } - protected int unblockPIN(CardChannel channel, PINSpec pinSpec, + protected int unblockPIN(CardChannel channel, PinInfo pinInfo, ModifyPINGUI provider, int retries) throws SignatureCardException, InterruptedException, CardException { @@ -726,27 +725,32 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu ResetRetryCounterAPDUSpec apduSpec = new ResetRetryCounterAPDUSpec( new byte[] { - (byte) 0x00, (byte) 0x2c, (byte) 0x00, pinSpec.getKID(), (byte) 0x10, + (byte) 0x00, (byte) 0x2c, (byte) 0x00, pinInfo.getKID(), (byte) 0x10, (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4, 8); - ResponseAPDU resp = reader.modify(channel, apduSpec, provider, pinSpec, retries); + ResponseAPDU resp = reader.modify(channel, apduSpec, provider, pinInfo, retries); if (resp.getSW() == 0x9000) { + pinInfo.setActive(pinInfo.maxRetries); return -1; } else if (resp.getSW() == 0x6983) { // PUK blocked throw new LockedException(); } else if (resp.getSW() == 0x6984) { + // PIN not active + pinInfo.setNotActive(); throw new NotActivatedException(); } else if (resp.getSW() >> 4 == 0x63c) { + // wrong PUK, return PUK retries return 0x0f & resp.getSW(); } else { String msg = "RESET RETRY COUNTER failed. SW=" + Integer.toHexString(resp.getSW()); log.error(msg); + pinInfo.setUnknown(); throw new SignatureCardException(msg); } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java index 73c7faa8..3318ab0f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -42,8 +42,8 @@ import java.util.Locale; import javax.smartcardio.Card; import javax.smartcardio.CardTerminal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.pin.gui.PINGUI; @@ -71,7 +71,7 @@ public class SWCard implements SignatureCard { private static String swCardDir; - private static Log log = LogFactory.getLog(SWCard.class); + private final Logger log = LoggerFactory.getLogger(SWCard.class); private KeyStore certifiedKeyStore; @@ -170,7 +170,7 @@ public class SWCard implements SignatureCard { // try to load KeyStore file String fileName = getFileName(keyStoreFileName); - log.info("Trying to load KeyStore from file '" + fileName + "'."); + log.info("Trying to load KeyStore from file '{}'.", fileName); FileInputStream keyStoreFile; try { @@ -313,7 +313,7 @@ public class SWCard implements SignatureCard { if (password == null) { - PINSpec pinSpec = new PINSpec(0, -1, ".", "KeyStore-Password", (byte) 0x01, null); + PinInfo pinSpec = new PinInfo(0, -1, ".", "at/gv/egiz/smcc/SWCard", "sw.pin", (byte) 0x01, null, PinInfo.UNKNOWN_RETRIES); password = provider.providePIN(pinSpec, -1); @@ -331,7 +331,7 @@ public class SWCard implements SignatureCard { for (Enumeration<String> aliases = keyStore.aliases(); aliases .hasMoreElements() && privateKey == null;) { String alias = aliases.nextElement(); - log.debug("Found alias '" + alias + "' in keystore"); + log.debug("Found alias '{}' in keystore.", alias); if (keyStore.isKeyEntry(alias)) { Key key = null; while (key == null) { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java index 9165a7d8..2cd0cc8a 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java @@ -25,8 +25,8 @@ import javax.smartcardio.ATR; import javax.smartcardio.Card; import javax.smartcardio.CardTerminal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A factory for creating {@link SignatureCard}s from {@link Card}s. @@ -127,7 +127,7 @@ public class SignatureCardFactory { /** * Logging facility. */ - private static Log log = LogFactory.getLog(SignatureCardFactory.class); + private final Logger log = LoggerFactory.getLogger(SignatureCardFactory.class); /** * The instance to be returned by {@link #getInstance()}. @@ -320,7 +320,62 @@ public class SignatureCardFactory { (byte) 0xff, (byte) 0xff, (byte) 0xff }, "at.gv.egiz.smcc.ITCard")); + // EstEID cards return different ATRs depending on the reader device + supportedCards.add(new SupportedCard( + // ATR + // (3B:5E:11:FF:45:73:74:45:49:44:20:76:65:72:20:31:2E:30) + new byte[] { (byte) 0x3b, (byte) 0x5e, (byte) 0x11, + (byte) 0xff, (byte) 0x45, (byte) 0x73, (byte) 0x74, + (byte) 0x45, (byte) 0x49, (byte) 0x44, (byte) 0x20, + (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x20, + (byte) 0x31, (byte) 0x2e, (byte) 0x30 }, + // mask + // (ff:ff:ff:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:00:00:00) + new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff }, + "at.gv.egiz.smcc.EstEIDCard")); + + // EstEID cards return different ATRs depending on the reader device + supportedCards.add(new SupportedCard( + // ATR + // (3B:DE:18:FF:C0:80:B1:FE:45:1F:03:45:73:74:45:49:44:20:76:65:72:20:31:2E:30:2B) + new byte[] { (byte) 0x3b, (byte) 0xde, (byte) 0x18, + (byte) 0xff, (byte) 0xc0, (byte) 0x80, (byte) 0xb1, + (byte) 0xfe, (byte) 0x45, (byte) 0x1f, (byte) 0x03, + (byte) 0x45, (byte) 0x73, (byte) 0x74, (byte) 0x45, + (byte) 0x49, (byte) 0x44, (byte) 0x20, (byte) 0x76, + (byte) 0x65, (byte) 0x72, (byte) 0x20, (byte) 0x31, + (byte) 0x2e, (byte) 0x30, (byte) 0x2b }, + // mask + // (ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:00:00:00) + new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff }, + "at.gv.egiz.smcc.EstEIDCard")); + supportedCards.add(new SupportedCard( + // ATR (3B:7D:95:00:00:80:31:80:65:B0:83:11:C0:A9:83:00:90:00 - + // 00:00:00:00) + new byte[] { (byte) 0x3b, (byte) 0x7d, (byte) 0x95, + (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x31, + (byte) 0x80, (byte) 0x65, (byte) 0xb0, (byte) 0x83, + (byte) 0x11, (byte) 0xc0, (byte) 0xa9, (byte) 0x83, + (byte) 0x00, (byte) 0x90, (byte) 0x00 }, + // mask + // (ff:ff:ff:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:00:00:00) + new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0x00, (byte) 0xff, (byte) 0x00 }, + "at.gv.egiz.smcc.PtEidCard")); } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java index 00dc2d0e..2e0de76b 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java @@ -17,17 +17,17 @@ package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; -import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.PinInfo; public interface ModifyPINGUI extends ModifyPINProvider { - void modifyPINDirect(PINSpec spec, int retries) throws CancelledException, InterruptedException; + void modifyPINDirect(PinInfo pinInfo, int retries) throws CancelledException, InterruptedException; void finishDirect(); - void enterCurrentPIN(PINSpec spec, int retries); - void enterNewPIN(PINSpec spec); - void confirmNewPIN(PINSpec spec); + void enterCurrentPIN(PinInfo pinInfo, int retries); + void enterNewPIN(PinInfo pinInfo); + void confirmNewPIN(PinInfo pinInfo); void validKeyPressed(); void correctionButtonPressed(); void allKeysCleared(); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java index 36f0097d..7933214b 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java @@ -17,7 +17,7 @@ package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; -import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.PinInfo; /** @@ -39,10 +39,10 @@ public interface ModifyPINProvider { * @throws at.gv.egiz.smcc.CancelledException if cancelled by user * @throws java.lang.InterruptedException */ - public char[] provideCurrentPIN(PINSpec spec, int retries) + public char[] provideCurrentPIN(PinInfo pinInfo, int retries) throws CancelledException, InterruptedException; - public char[] provideNewPIN(PINSpec spec) + public char[] provideNewPIN(PinInfo pinInfo) throws CancelledException, InterruptedException; } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java index 5199977b..92b9f14d 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java @@ -17,7 +17,7 @@ package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; -import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.PinInfo; /** @@ -27,13 +27,13 @@ import at.gv.egiz.smcc.PINSpec; */ public interface PINGUI extends PINProvider { - void enterPINDirect(PINSpec spec, int retries) + void enterPINDirect(PinInfo pinInfo, int retries) throws CancelledException, InterruptedException; /** * @throws CancelledException, InterruptedException if signature-data dialog is interrupted or cancelled */ - void enterPIN(PINSpec spec, int retries) + void enterPIN(PinInfo pinInfo, int retries) throws CancelledException, InterruptedException; void validKeyPressed(); void correctionButtonPressed(); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java index 7443ee30..e8641797 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java @@ -17,7 +17,7 @@ package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; -import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.PinInfo; /** @@ -45,7 +45,7 @@ public interface PINProvider { * @throws at.gv.egiz.smcc.CancelledException * @throws java.lang.InterruptedException */ - char[] providePIN(PINSpec pinSpec, int retries) + char[] providePIN(PinInfo pinSpec, int retries) throws CancelledException, InterruptedException; } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java index a1246dd6..6c5e939b 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java @@ -23,7 +23,7 @@ import javax.smartcardio.ResponseAPDU; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec; import at.gv.egiz.smcc.NewReferenceDataAPDUSpec; -import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.ResetRetryCounterAPDUSpec; import at.gv.egiz.smcc.SignatureCardException; import at.gv.egiz.smcc.VerifyAPDUSpec; @@ -38,7 +38,7 @@ import javax.smartcardio.Card; public interface CardReader { - String[] FEATURES = new String[]{"NO_FEATURE", + static final String[] FEATURES = new String[]{"NO_FEATURE", "FEATURE_VERIFY_PIN_START", "FEATURE_VERIFY_PIN_FINISH", "FEATURE_MODIFY_PIN_START", @@ -57,16 +57,16 @@ public interface CardReader { "FEATURE_GET_KEY", "FEATURE_IFD_DISPLAY_PROPERTIES"}; - Byte FEATURE_VERIFY_PIN_START = new Byte((byte) 0x01); - Byte FEATURE_VERIFY_PIN_FINISH = new Byte((byte) 0x02); - Byte FEATURE_MODIFY_PIN_START = new Byte((byte) 0x03); - Byte FEATURE_MODIFY_PIN_FINISH = new Byte((byte) 0x04); - Byte FEATURE_GET_KEY_PRESSED = new Byte((byte) 0x05); - Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 0x06); - Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 0x07); - Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 0x08); - Byte FEATURE_MCT_UNIVERSAL = new Byte((byte) 0x09); - Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 0x0a); + static final Byte FEATURE_VERIFY_PIN_START = new Byte((byte) 0x01); + static final Byte FEATURE_VERIFY_PIN_FINISH = new Byte((byte) 0x02); + static final Byte FEATURE_MODIFY_PIN_START = new Byte((byte) 0x03); + static final Byte FEATURE_MODIFY_PIN_FINISH = new Byte((byte) 0x04); + static final Byte FEATURE_GET_KEY_PRESSED = new Byte((byte) 0x05); + static final Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 0x06); + static final Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 0x07); + static final Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 0x08); + static final Byte FEATURE_MCT_UNIVERSAL = new Byte((byte) 0x09); + static final Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 0x0a); //TODO continue list @@ -75,18 +75,18 @@ public interface CardReader { boolean hasFeature(Byte feature); ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec, - PINGUI pinGUI, PINSpec pinSpec, int retries) + PINGUI pinGUI, PinInfo pinInfo, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException; ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + ModifyPINGUI pinGUI, PinInfo pinInfo, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException; ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec) + ModifyPINGUI pinGUI, PinInfo pinInfo) throws CancelledException, InterruptedException, CardException, SignatureCardException; ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + ModifyPINGUI pinGUI, PinInfo pinInfo, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException; } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java index 03a794fe..cc25a63c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java @@ -23,12 +23,12 @@ import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec; import at.gv.egiz.smcc.NewReferenceDataAPDUSpec; -import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.ResetRetryCounterAPDUSpec; import at.gv.egiz.smcc.SignatureCardException; import at.gv.egiz.smcc.VerifyAPDUSpec; @@ -42,7 +42,7 @@ import at.gv.egiz.smcc.util.ISO7816Utils; */ public class DefaultCardReader implements CardReader { - protected final static Log log = LogFactory.getLog(DefaultCardReader.class); + private final Logger log = LoggerFactory.getLogger(DefaultCardReader.class); protected CardTerminal ct; protected String name; @@ -57,7 +57,7 @@ public class DefaultCardReader implements CardReader { @Override public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec, - PINGUI pinGUI, PINSpec pinSpec, int retries) + PINGUI pinGUI, PinInfo pinSpec, int retries) throws SignatureCardException, CardException, InterruptedException { log.debug("VERIFY"); @@ -66,7 +66,7 @@ public class DefaultCardReader implements CardReader { @Override public ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + ModifyPINGUI pinGUI, PinInfo pinSpec, int retries) throws SignatureCardException, CardException, InterruptedException { log.debug("MODIFY (CHANGE_REFERENCE_DATA)"); char[] oldPIN = pinGUI.provideCurrentPIN(pinSpec, retries); @@ -76,7 +76,7 @@ public class DefaultCardReader implements CardReader { @Override public ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec) + ModifyPINGUI pinGUI, PinInfo pinSpec) throws SignatureCardException, CardException, InterruptedException { log.debug("MODIFY (NEW_REFERENCE_DATA)"); char[] newPIN = pinGUI.provideNewPIN(pinSpec); @@ -85,7 +85,7 @@ public class DefaultCardReader implements CardReader { @Override public ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + ModifyPINGUI pinGUI, PinInfo pinSpec, int retries) throws InterruptedException, CardException, SignatureCardException { log.debug("MODIFY (RESET_RETRY_COUNTER)"); //TODO diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java index c2537af8..3584af53 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java @@ -26,8 +26,8 @@ import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec; @@ -35,7 +35,7 @@ import at.gv.egiz.smcc.NewReferenceDataAPDUSpec; import at.gv.egiz.smcc.PINConfirmationException; import at.gv.egiz.smcc.PINFormatException; import at.gv.egiz.smcc.PINOperationAbortedException; -import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.ResetRetryCounterAPDUSpec; import at.gv.egiz.smcc.SignatureCardException; import at.gv.egiz.smcc.TimeoutException; @@ -52,13 +52,13 @@ public class PinpadCardReader extends DefaultCardReader { public static final int PIN_ENTRY_POLLING_INTERVAL = 10; - protected final static Log log = LogFactory.getLog(PinpadCardReader.class); + private final Logger log = LoggerFactory.getLogger(PinpadCardReader.class); protected byte bEntryValidationCondition = 0x02; // validation key pressed protected byte bTimeOut = 0x3c; // 60sec (= max on ReinerSCT) protected byte bTimeOut2 = 0x00; // default (attention with SCM) - protected byte wPINMaxExtraDigitH = 0x00; // min pin length zero digits - protected byte wPINMaxExtraDigitL = 0x0c; // max pin length 12 digits + protected byte wPINMaxExtraDigitMin = 0x00; // min pin length zero digits + protected byte wPINMaxExtraDigitMax = 0x0c; // max pin length 12 digits /** * supported features and respective control codes @@ -99,21 +99,21 @@ public class PinpadCardReader extends DefaultCardReader { //Snow Leopard: Reiner-SCT cyberJack pinpad(a) 00 00 //display: REINER SCT CyberJack 00 00 if(name.startsWith("gemplus gempc pinpad") || name.startsWith("gemalto gempc pinpad")) { - log.debug("setting custom wPINMaxExtraDigitH (0x04) for " + name); - wPINMaxExtraDigitH = 0x04; - log.debug("setting custom wPINMaxExtraDigitL (0x08) for " + name); - wPINMaxExtraDigitL = 0x08; + log.trace("Setting custom wPINMaxExtraDigitH (0x04) for {}.", name); + wPINMaxExtraDigitMin = 0x04; + log.trace("Setting custom wPINMaxExtraDigitL (0x08) for {}.", name); + wPINMaxExtraDigitMax = 0x08; } else if (name.startsWith("omnikey cardman 3621")) { - log.debug("setting custom wPINMaxExtraDigitH (0x01) for " + name); - wPINMaxExtraDigitH = 0x01; + log.trace("Setting custom wPINMaxExtraDigitH (0x01) for {}.", name); + wPINMaxExtraDigitMin = 0x01; } else if (name.startsWith("scm spr 532") || name.startsWith("scm microsystems inc. sprx32 usb smart card reader")) { - log.debug("setting custom bTimeOut (0x3c) for " + name); + log.trace("Setting custom bTimeOut (0x3c) for {}.", name); bTimeOut = 0x3c; - log.debug("setting custom bTimeOut2 (0x0f) for " + name); + log.trace("Setting custom bTimeOut2 (0x0f) for {}.", name); bTimeOut2 = 0x0f; } else if (name.startsWith("cherry smartboard xx44")) { - log.debug("setting custom wPINMaxExtraDigitH (0x01) for " + name); - wPINMaxExtraDigitH = 0x01; + log.trace("Setting custom wPINMaxExtraDigitH (0x01) for {}.", name); + wPINMaxExtraDigitMin = 0x01; } } @@ -127,17 +127,17 @@ public class PinpadCardReader extends DefaultCardReader { private void VERIFY_PIN_START(Card icc, byte[] PIN_VERIFY) throws CardException { int ioctl = features.get(FEATURE_VERIFY_PIN_START); if (log.isTraceEnabled()) { - log.trace("VERIFY_PIN_START (" + Integer.toHexString(ioctl) + - ") " + SMCCHelper.toString(PIN_VERIFY)); + log.trace("VERIFY_PIN_START ({}) {}", Integer.toHexString(ioctl), + SMCCHelper.toString(PIN_VERIFY)); } byte[] resp = icc.transmitControlCommand(ioctl, PIN_VERIFY); if (resp != null && resp.length > 0) { if (resp[0] == (byte) 0x57) { - log.error("Invalid parameter in PIN_VERIFY structure"); + log.error("Invalid parameter in PIN_VERIFY structure."); throw new CardException("ERROR_INVALID_PARAMETER"); } else { - log.error("unexpected response to VERIFY_PIN_START: " + - SMCCHelper.toString(resp)); + log.error("Unexpected response to VERIFY_PIN_START: {}.", SMCCHelper + .toString(resp)); throw new CardException("unexpected response to VERIFY_PIN_START: " + SMCCHelper.toString(resp)); } @@ -153,7 +153,7 @@ public class PinpadCardReader extends DefaultCardReader { // } return resp[0]; } - log.error("unexpected response to GET_KEY_PRESSED: " + + log.error("Unexpected response to GET_KEY_PRESSED: {}.", SMCCHelper.toString(resp)); throw new CardException("unexpected response to GET_KEY_PRESSED: " + SMCCHelper.toString(resp)); @@ -162,16 +162,16 @@ public class PinpadCardReader extends DefaultCardReader { private byte[] VERIFY_PIN_FINISH(Card icc) throws CardException { int ioctl = features.get(FEATURE_VERIFY_PIN_FINISH); if (log.isTraceEnabled()) { - log.trace("VERIFY_PIN_FINISH (" + Integer.toHexString(ioctl) + ")"); + log.trace("VERIFY_PIN_FINISH ({})", Integer.toHexString(ioctl)); } byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); if (resp != null && resp.length == 2) { if (log.isTraceEnabled()) { - log.trace("response " + SMCCHelper.toString(resp)); + log.trace("response {}", SMCCHelper.toString(resp)); } return resp; } - log.error("unexpected response to VERIFY_PIN_FINISH: " + + log.error("Unexpected response to VERIFY_PIN_FINISH: {}.", SMCCHelper.toString(resp)); throw new CardException("unexpected response to VERIFY_PIN_FINISH: " + SMCCHelper.toString(resp)); @@ -186,10 +186,10 @@ public class PinpadCardReader extends DefaultCardReader { byte[] resp = icc.transmitControlCommand(ioctl, PIN_MODIFY); if (resp != null && resp.length > 0) { if (resp[0] == (byte) 0x57) { - log.error("Invalid parameter in PIN_MODIFY structure"); + log.error("Invalid parameter in PIN_MODIFY structure."); throw new CardException("ERROR_INVALID_PARAMETER"); } else { - log.error("unexpected response to MODIFY_PIN_START: " + + log.error("Unexpected response to MODIFY_PIN_START: {}.", SMCCHelper.toString(resp)); throw new CardException("unexpected response to MODIFY_PIN_START: " + SMCCHelper.toString(resp)); @@ -200,16 +200,16 @@ public class PinpadCardReader extends DefaultCardReader { private byte[] MODIFY_PIN_FINISH(Card icc) throws CardException { int ioctl = features.get(FEATURE_MODIFY_PIN_FINISH); if (log.isTraceEnabled()) { - log.trace("MODIFY_PIN_FINISH (" + Integer.toHexString(ioctl) + ")"); + log.trace("MODIFY_PIN_FINISH ({})", Integer.toHexString(ioctl)); } byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); if (resp != null && resp.length == 2) { if (log.isTraceEnabled()) { - log.trace("response " + SMCCHelper.toString(resp)); + log.trace("response {}", SMCCHelper.toString(resp)); } return resp; } - log.error("unexpected response to MODIFY_PIN_FINISH: " + + log.error("Unexpected response to MODIFY_PIN_FINISH: {}", SMCCHelper.toString(resp)); throw new CardException("unexpected response to MODIFY_PIN_FINISH: " + SMCCHelper.toString(resp)); @@ -218,12 +218,12 @@ public class PinpadCardReader extends DefaultCardReader { private byte[] VERIFY_PIN_DIRECT(Card icc, byte[] PIN_VERIFY) throws CardException { int ioctl = features.get(FEATURE_VERIFY_PIN_DIRECT); if (log.isTraceEnabled()) { - log.trace("VERIFY_PIN_DIRECT (" + Integer.toHexString(ioctl) + - ") " + SMCCHelper.toString(PIN_VERIFY)); + log.trace("VERIFY_PIN_DIRECT ({}) {}", Integer.toHexString(ioctl), + SMCCHelper.toString(PIN_VERIFY)); } byte[] resp = icc.transmitControlCommand(ioctl, PIN_VERIFY); if (log.isTraceEnabled()) { - log.trace("response " + SMCCHelper.toString(resp)); + log.trace("response {}", SMCCHelper.toString(resp)); } return resp; } @@ -233,7 +233,7 @@ public class PinpadCardReader extends DefaultCardReader { // pinGUI.enterPIN(pinSpec, retries); - log.debug("VERIFY_PIN_START [" + FEATURES[FEATURE_VERIFY_PIN_START] + "]"); + log.debug("VERIFY_PIN_START [{}]", FEATURES[FEATURE_VERIFY_PIN_START]); VERIFY_PIN_START(icc, PIN_VERIFY); byte resp; @@ -248,29 +248,29 @@ public class PinpadCardReader extends DefaultCardReader { } } } else if (resp == (byte) 0x0d) { - log.debug("GET_KEY_PRESSED: 0x0d (user confirmed)"); + log.trace("GET_KEY_PRESSED: 0x0d (user confirmed)"); break; } else if (resp == (byte) 0x2b) { log.trace("GET_KEY_PRESSED: 0x2b (user entered valid key 0-9)"); pinGUI.validKeyPressed(); } else if (resp == (byte) 0x1b) { - log.debug("GET_KEY_PRESSED: 0x1b (user cancelled VERIFY_PIN via cancel button)"); + log.trace("GET_KEY_PRESSED: 0x1b (user cancelled VERIFY_PIN via cancel button)"); break; // returns 0x6401 } else if (resp == (byte) 0x08) { - log.debug("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)"); + log.trace("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)"); pinGUI.correctionButtonPressed(); } else if (resp == (byte) 0x0e) { - log.debug("GET_KEY_PRESSED: 0x0e (timeout occured)"); + log.trace("GET_KEY_PRESSED: 0x0e (timeout occured)"); break; // return 0x6400 } else if (resp == (byte) 0x40) { - log.debug("GET_KEY_PRESSED: 0x40 (PIN_Operation_Aborted)"); + log.trace("GET_KEY_PRESSED: 0x40 (PIN_Operation_Aborted)"); throw new PINOperationAbortedException("PIN_Operation_Aborted (0x40)"); } else if (resp == (byte) 0x0a) { - log.debug("GET_KEY_PRESSED: 0x0a (all keys cleared"); + log.trace("GET_KEY_PRESSED: 0x0a (all keys cleared"); pinGUI.allKeysCleared(); } else { - log.error("unexpected response to GET_KEY_PRESSED: " + - Integer.toHexString(resp)); + log.error("Unexpected response to GET_KEY_PRESSED: {}.", Integer + .toHexString(resp)); throw new CardException("unexpected response to GET_KEY_PRESSED: " + Integer.toHexString(resp)); } @@ -283,7 +283,7 @@ public class PinpadCardReader extends DefaultCardReader { * does not display the first pin dialog (enterCurrentPIN or enterNewPIN, depends on bConfirmPIN), * since this is easier to do in calling modify() */ - private byte[] modifyPin(Card icc, byte[] PIN_MODIFY, ModifyPINGUI pinGUI, PINSpec pINSpec) + private byte[] modifyPin(Card icc, byte[] PIN_MODIFY, ModifyPINGUI pinGUI, PinInfo pINSpec) throws PINOperationAbortedException, CardException { byte pinConfirmations = (byte) 0x00; //b0: new pin not entered (0) / entered (1) @@ -298,7 +298,7 @@ public class PinpadCardReader extends DefaultCardReader { // pinGUI.enterCurrentPIN(pINSpec, retries); // } - log.debug("MODIFY_PIN_START [" + FEATURES[FEATURE_MODIFY_PIN_START] + "]"); + log.debug("MODIFY_PIN_START [{}]", FEATURES[FEATURE_MODIFY_PIN_START]); MODIFY_PIN_START(icc, PIN_MODIFY); byte resp; @@ -309,13 +309,13 @@ public class PinpadCardReader extends DefaultCardReader { try { wait(PIN_ENTRY_POLLING_INTERVAL); } catch (InterruptedException ex) { - log.error("interrupted in MODIFY_PIN"); + log.error("Interrupted in MODIFY_PIN"); } } } else if (resp == (byte) 0x0d) { if (log.isTraceEnabled()) { - log.trace("requested pin confirmations: 0b" + Integer.toBinaryString(bConfirmPIN & 0xff)); - log.trace("performed pin confirmations: 0b" + Integer.toBinaryString(pinConfirmations & 0xff)); + log.trace("requested pin confirmations: 0b{}", Integer.toBinaryString(bConfirmPIN & 0xff)); + log.trace("performed pin confirmations: 0b{}", Integer.toBinaryString(pinConfirmations & 0xff)); } log.debug("GET_KEY_PRESSED: 0x0d (user confirmed)"); if (pinConfirmations == bConfirmPIN) { @@ -337,23 +337,23 @@ public class PinpadCardReader extends DefaultCardReader { log.trace("GET_KEY_PRESSED: 0x2b (user entered valid key 0-9)"); pinGUI.validKeyPressed(); } else if (resp == (byte) 0x1b) { - log.debug("GET_KEY_PRESSED: 0x1b (user cancelled VERIFY_PIN via cancel button)"); + log.trace("GET_KEY_PRESSED: 0x1b (user cancelled VERIFY_PIN via cancel button)"); break; // returns 0x6401 } else if (resp == (byte) 0x08) { - log.debug("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)"); + log.trace("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)"); pinGUI.correctionButtonPressed(); } else if (resp == (byte) 0x0e) { - log.debug("GET_KEY_PRESSED: 0x0e (timeout occured)"); + log.trace("GET_KEY_PRESSED: 0x0e (timeout occured)"); break; // return 0x6400 } else if (resp == (byte) 0x40) { - log.debug("GET_KEY_PRESSED: 0x40 (PIN_Operation_Aborted)"); + log.trace("GET_KEY_PRESSED: 0x40 (PIN_Operation_Aborted)"); throw new PINOperationAbortedException("PIN_Operation_Aborted (0x40)"); } else if (resp == (byte) 0x0a) { - log.debug("GET_KEY_PRESSED: 0x0a (all keys cleared"); + log.trace("GET_KEY_PRESSED: 0x0a (all keys cleared"); pinGUI.allKeysCleared(); } else { - log.error("unexpected response to GET_KEY_PRESSED: " + - Integer.toHexString(resp)); + log.error("Unexpected response to GET_KEY_PRESSED: {}.", Integer + .toHexString(resp)); throw new CardException("unexpected response to GET_KEY_PRESSED: " + Integer.toHexString(resp)); } @@ -367,17 +367,17 @@ public class PinpadCardReader extends DefaultCardReader { private byte[] MODIFY_PIN_DIRECT(Card icc, byte[] PIN_MODIFY) throws CardException { int ioctl = features.get(FEATURE_MODIFY_PIN_DIRECT); if (log.isTraceEnabled()) { - log.trace("MODIFY_PIN_DIRECT (" + Integer.toHexString(ioctl) + - ") " + SMCCHelper.toString(PIN_MODIFY)); + log.trace("MODIFY_PIN_DIRECT ({}) {}", Integer.toHexString(ioctl), + SMCCHelper.toString(PIN_MODIFY)); } byte[] resp = icc.transmitControlCommand(ioctl, PIN_MODIFY); if (log.isTraceEnabled()) { - log.trace("response " + SMCCHelper.toString(resp)); + log.trace("response {}", SMCCHelper.toString(resp)); } return resp; } - protected byte[] createPINModifyStructure(NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) { + protected byte[] createPINModifyStructure(NewReferenceDataAPDUSpec apduSpec, PinInfo pinSpec) { ByteArrayOutputStream s = new ByteArrayOutputStream(); // bTimeOut @@ -399,16 +399,17 @@ public class PinpadCardReader extends DefaultCardReader { s.write(0x00); // bInsertionOffsetNew s.write(apduSpec.getPinInsertionOffsetNew()); - // wPINMaxExtraDigit - s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL)); - s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH)); + // wPINMaxExtraDigit (little endian) + s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitMax)); + s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitMin)); // bConfirmPIN s.write(0x01); // bEntryValidationCondition s.write(bEntryValidationCondition); // bNumberMessage s.write(0x02); - // wLangId English (United States), see http://www.usb.org/developers/docs/USB_LANGIDs.pdf + // wLangId (little endian) + // English (United States), see http://www.usb.org/developers/docs/USB_LANGIDs.pdf s.write(0x09); s.write(0x04); // bMsgIndex1 @@ -440,7 +441,7 @@ public class PinpadCardReader extends DefaultCardReader { } - protected byte[] createPINModifyStructure(ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) { + protected byte[] createPINModifyStructure(ChangeReferenceDataAPDUSpec apduSpec, PinInfo pinSpec) { //TODO bInsertionOffsetOld (0x00), bConfirmPIN (0x01), bNumberMessage (0x02), bMsgIndex1/2/3 ByteArrayOutputStream s = new ByteArrayOutputStream(); @@ -464,8 +465,8 @@ public class PinpadCardReader extends DefaultCardReader { // bInsertionOffsetNew s.write(apduSpec.getPinInsertionOffsetNew()); // wPINMaxExtraDigit - s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL)); - s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH)); + s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitMax)); + s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitMin)); // bConfirmPIN s.write(0x03); // bEntryValidationCondition @@ -504,7 +505,7 @@ public class PinpadCardReader extends DefaultCardReader { } - protected byte[] createPINVerifyStructure(VerifyAPDUSpec apduSpec, PINSpec pinSpec) { + protected byte[] createPINVerifyStructure(VerifyAPDUSpec apduSpec, PinInfo pinSpec) { ByteArrayOutputStream s = new ByteArrayOutputStream(); // bTimeOut @@ -522,14 +523,14 @@ public class PinpadCardReader extends DefaultCardReader { // bmPINLengthFormat s.write(// system unit = bit (0xF & apduSpec.getPinLengthPos())); - // wPINMaxExtraDigit - s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL)); // max PIN length - s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH)); // min PIN length + // wPINMaxExtraDigit (little endian) + s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitMax)); // max PIN length + s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitMin)); // min PIN length // bEntryValidationCondition s.write(bEntryValidationCondition); // bNumberMessage s.write(0x01); - // wLangId + // wLangId (little endian) s.write(0x09); s.write(0x04); // bMsgIndex @@ -558,7 +559,7 @@ public class PinpadCardReader extends DefaultCardReader { @Override public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec, - PINGUI pinGUI, PINSpec pinSpec, int retries) + PINGUI pinGUI, PinInfo pinSpec, int retries) throws SignatureCardException, CardException, InterruptedException { ResponseAPDU resp = null; @@ -571,10 +572,10 @@ public class PinpadCardReader extends DefaultCardReader { resp = new ResponseAPDU(verifyPin(icc, s, pinGUI)); } else if (VERIFY_DIRECT) { pinGUI.enterPINDirect(pinSpec, retries); - log.debug("VERIFY_PIN_DIRECT [" + FEATURES[FEATURE_VERIFY_PIN_DIRECT] + "]"); + log.debug("VERIFY_PIN_DIRECT [{}]", FEATURES[FEATURE_VERIFY_PIN_DIRECT]); resp = new ResponseAPDU(VERIFY_PIN_DIRECT(icc, s)); } else { - log.warn("falling back to default pin-entry"); + log.warn("Falling back to default pin-entry."); return super.verify(channel, apduSpec, pinGUI, pinSpec, retries); } @@ -586,9 +587,9 @@ public class PinpadCardReader extends DefaultCardReader { log.debug("SPE operation was cancelled by the 'Cancel' button."); throw new CancelledException(); case 0x6403: - log.debug("User entered too short or too long PIN " - + "regarding MIN/MAX PIN length."); - throw new PINFormatException(); + log.debug("User entered too short or too long PIN " + + "regarding MIN/MAX PIN length."); + throw new PINFormatException(); case 0x6480: log.debug("SPE operation was aborted by the 'Cancel' operation " + "at the host system."); @@ -601,7 +602,7 @@ public class PinpadCardReader extends DefaultCardReader { @Override public ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + ModifyPINGUI pinGUI, PinInfo pinSpec, int retries) throws SignatureCardException, CardException, InterruptedException { ResponseAPDU resp = null; @@ -614,10 +615,10 @@ public class PinpadCardReader extends DefaultCardReader { resp = new ResponseAPDU(modifyPin(icc, s, pinGUI, pinSpec)); } else if (MODIFY_DIRECT) { pinGUI.modifyPINDirect(pinSpec, retries); - log.debug("MODIFY_PIN_DIRECT [" + FEATURES[FEATURE_MODIFY_PIN_DIRECT] + "]"); + log.debug("MODIFY_PIN_DIRECT [{}]", FEATURES[FEATURE_MODIFY_PIN_DIRECT]); resp = new ResponseAPDU(MODIFY_PIN_DIRECT(icc, s)); } else { - log.warn("falling back to default pin-entry"); + log.warn("Falling back to default pin-entry."); return super.modify(channel, apduSpec, pinGUI, pinSpec, retries); } @@ -648,7 +649,7 @@ public class PinpadCardReader extends DefaultCardReader { @Override public ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec) + ModifyPINGUI pinGUI, PinInfo pinSpec) throws SignatureCardException, CardException, InterruptedException { ResponseAPDU resp = null; @@ -661,10 +662,10 @@ public class PinpadCardReader extends DefaultCardReader { resp = new ResponseAPDU(modifyPin(icc, s, pinGUI, pinSpec)); } else if (MODIFY_DIRECT) { pinGUI.modifyPINDirect(pinSpec, -1); - log.debug("MODIFY_PIN_DIRECT [" + FEATURES[FEATURE_MODIFY_PIN_DIRECT] + "]"); + log.debug("MODIFY_PIN_DIRECT [{}]", FEATURES[FEATURE_MODIFY_PIN_DIRECT]); resp = new ResponseAPDU(MODIFY_PIN_DIRECT(icc, s)); } else { - log.warn("falling back to default pin-entry"); + log.warn("Falling back to default pin-entry."); return super.modify(channel, apduSpec, pinGUI, pinSpec); } @@ -695,7 +696,7 @@ public class PinpadCardReader extends DefaultCardReader { @Override public ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec, - ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + ModifyPINGUI pinGUI, PinInfo pinSpec, int retries) throws InterruptedException, CardException, SignatureCardException { //TODO return modify(channel, (ChangeReferenceDataAPDUSpec) apduSpec, pinGUI, pinSpec, retries); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java index bf1730e9..0d0a8d8a 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java @@ -25,8 +25,8 @@ import java.util.Map; import javax.smartcardio.Card; import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -34,7 +34,7 @@ import org.apache.commons.logging.LogFactory; */ public class ReaderFactory { - protected final static Log log = LogFactory.getLog(ReaderFactory.class); + private final Logger log = LoggerFactory.getLogger(ReaderFactory.class); protected static SMCCConfiguration configuration; @@ -50,8 +50,9 @@ public class ReaderFactory { public static CardReader getReader(Card icc, CardTerminal ct) { + Logger log = LoggerFactory.getLogger(ReaderFactory.class); String name = ct.getName(); - log.info("creating reader " + name); + log.info("Creating reader : {}.", name); Map<Byte, Integer> features; if (configuration != null && configuration.isDisablePinpad()) { @@ -70,33 +71,31 @@ public class ReaderFactory { return reader; } - private static int CTL_CODE(int code) { + private static int SCARD_CTL_CODE(int code) { String os_name = System.getProperty("os.name").toLowerCase(); if (os_name.indexOf("windows") > -1) { - // cf. WinIOCTL.h return (0x31 << 16 | (code) << 2); } - // cf. reader.h return 0x42000000 + (code); } - static int IOCTL_GET_FEATURE_REQUEST = CTL_CODE(3400); + static int IOCTL_GET_FEATURE_REQUEST = SCARD_CTL_CODE(3400); private static Map<Byte, Integer> queryFeatures(Card icc) { + Logger log = LoggerFactory.getLogger(ReaderFactory.class); Map<Byte, Integer> features = new HashMap<Byte, Integer>(); - if (icc == null) { - log.warn("invalid card handle, cannot query ifd features"); + log.warn("Invalid card handle, cannot query ifd features."); } else { try { if (log.isTraceEnabled()) { - log.trace("GET_FEATURE_REQUEST " + Integer.toHexString(IOCTL_GET_FEATURE_REQUEST)); + log.trace("GET_FEATURE_REQUEST {}", Integer.toHexString(IOCTL_GET_FEATURE_REQUEST)); } byte[] resp = icc.transmitControlCommand(IOCTL_GET_FEATURE_REQUEST, new byte[0]); if (log.isTraceEnabled()) { - log.trace("Response TLV " + SMCCHelper.toString(resp)); + log.trace("Response TLV {}", SMCCHelper.toString(resp)); } // tag // length in bytes (always 4) @@ -108,15 +107,14 @@ public class ReaderFactory { ((0xff & resp[i + 4]) << 8) | (0xff & resp[i + 5]); if (log.isInfoEnabled()) { - log.info("IFD supports " + CardReader.FEATURES[feature.intValue()] + - ": " + Integer.toHexString(ioctl.intValue())); + log.info("IFD supports {}: {}", CardReader.FEATURES[feature + .intValue()], Integer.toHexString(ioctl.intValue())); } features.put(feature, ioctl); } } catch (CardException ex) { - log.debug("Failed to query IFD features: " + ex.getMessage()); - log.trace(ex); - log.info("IFD does not support secure pin entry"); + log.debug("Failed to query IFD features: {}", ex.getMessage(), ex); + log.info("IFD does not support secure pin entry."); } } return features; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java b/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java index fcd0b876..05249a5e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java @@ -286,12 +286,18 @@ public class ISO7816Utils { public static CommandAPDU createVerifyAPDU(VerifyAPDUSpec apduSpec, char[] pin) { // format pin - byte[] fpin = new byte[apduSpec.getPinLength()]; - byte[] mask = new byte[apduSpec.getPinLength()]; + int l = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : pin.length; + byte[] fpin = new byte[l]; + byte[] mask = new byte[l]; formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, pin); - byte[] apdu = apduSpec.getApdu(); - + byte[] template = apduSpec.getApdu(); + byte[] apdu = new byte[Math.max(template.length, 5 + apduSpec.getPinPosition() + l)]; + System.arraycopy(template, 0, apdu, 0, template.length); + if (template.length < 5) { + apdu[4] = (byte) (apdu.length - 5); + } + // insert formated pin insertPIN(apdu, apduSpec.getPinPosition() + 5, fpin, mask); @@ -307,13 +313,24 @@ public class ISO7816Utils { public static CommandAPDU createChangeReferenceDataAPDU( ChangeReferenceDataAPDUSpec apduSpec, char[] oldPin, char[] newPin) { + int lo = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : oldPin.length; + int ln = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : newPin.length; + // format old pin - byte[] fpin = new byte[apduSpec.getPinLength()]; - byte[] mask = new byte[apduSpec.getPinLength()]; + byte[] fpin = new byte[lo]; + byte[] mask = new byte[lo]; formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, oldPin); - byte[] apdu = apduSpec.getApdu(); - + byte[] template = apduSpec.getApdu(); + byte[] apdu = new byte[Math.max(template.length, + 5 + apduSpec.getPinPosition() + + Math.max(apduSpec.getPinInsertionOffsetOld() + lo, + apduSpec.getPinInsertionOffsetNew() + ln))]; + System.arraycopy(template, 0, apdu, 0, template.length); + if (template.length < 5) { + apdu[4] = (byte) (apdu.length - 5); + } + // insert formated old pin insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetOld() + 5, fpin, mask); @@ -324,8 +341,8 @@ public class ISO7816Utils { } // format new pin - fpin = new byte[apduSpec.getPinLength()]; - mask = new byte[apduSpec.getPinLength()]; + fpin = new byte[ln]; + mask = new byte[ln]; formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, newPin); // insert formated new pin @@ -345,12 +362,18 @@ public class ISO7816Utils { NewReferenceDataAPDUSpec apduSpec, char[] newPin) { // format old pin - byte[] fpin = new byte[apduSpec.getPinLength()]; - byte[] mask = new byte[apduSpec.getPinLength()]; + int l = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : newPin.length; + byte[] fpin = new byte[l]; + byte[] mask = new byte[l]; formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, newPin); - byte[] apdu = apduSpec.getApdu(); - + byte[] template = apduSpec.getApdu(); + byte[] apdu = new byte[Math.max(template.length, 5 + apduSpec.getPinPosition() + l)]; + System.arraycopy(template, 0, apdu, 0, template.length); + if (template.length < 5) { + apdu[4] = (byte) (apdu.length - 5); + } + // insert formated new pin insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetNew() + 5, fpin, mask); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java b/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java index f7d3bab7..a06fb624 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java @@ -14,137 +14,137 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package at.gv.egiz.smcc.util;
-
-import java.util.Locale;
-import java.util.Map;
-
-import javax.smartcardio.ATR;
-import javax.smartcardio.Card;
-import javax.smartcardio.CardTerminal;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import at.gv.egiz.smcc.CardNotSupportedException;
-import at.gv.egiz.smcc.SignatureCard;
-import at.gv.egiz.smcc.SignatureCardFactory;
-
-public class SMCCHelper {
-
- public final static int NO_CARD = 0;
- public final static int PC_SC_NOT_SUPPORTED = 1;
- public final static int TERMINAL_NOT_PRESENT = 2;
- public final static int CARD_NOT_SUPPORTED = 3;
- public final static int CARD_FOUND = 4;
-
- private final static Log log = LogFactory.getLog(SMCCHelper.class);
-
- protected SmartCardIO smartCardIO = new SmartCardIO();
- protected int resultCode = NO_CARD;
- protected SignatureCard signatureCard = null;
- protected static boolean useSWCard = false;
-
- public SMCCHelper() {
- update();
- }
-
- public synchronized void update() {
- update(-1);
- }
-
- public synchronized void update(int sleep) {
- SignatureCardFactory factory = SignatureCardFactory.getInstance();
- if (useSWCard) {
- try {
- signatureCard = factory.createSignatureCard(null, null);
- resultCode = CARD_FOUND;
- } catch (CardNotSupportedException e) {
- resultCode = CARD_NOT_SUPPORTED;
- signatureCard = null;
- }
- return;
- }
- signatureCard = null;
- resultCode = NO_CARD;
- // find pcsc support
- if (smartCardIO.isPCSCSupported()) {
- // find supported card
- if (smartCardIO.isTerminalPresent()) {
- Map<CardTerminal, Card> newCards = null;
- if (sleep > 0) {
- smartCardIO.waitForInserted(sleep);
-
- }
- newCards = smartCardIO.getCards();
- for (CardTerminal cardTerminal : newCards.keySet()) {
- try {
- Card c = newCards.get(cardTerminal);
- if (c == null) {
- throw new CardNotSupportedException();
- }
- signatureCard = factory.createSignatureCard(c, cardTerminal);
- ATR atr = newCards.get(cardTerminal).getATR();
- log.trace("Found supported card (" + signatureCard.toString() + ") "
- + "in terminal '" + cardTerminal.getName() + "', ATR = "
- + toString(atr.getBytes()) + ".");
- resultCode = CARD_FOUND;
- break;
-
- } catch (CardNotSupportedException e) {
- Card c = newCards.get(cardTerminal);
- if (c != null) {
- ATR atr = c.getATR();
- log.info("Found unsupported card" + " in terminal '"
- + cardTerminal.getName() + "', ATR = "
- + toString(atr.getBytes()) + ".");
- } else {
- log.info("Found unsupported card in terminal '"
- + cardTerminal.getName() + "' without ATR");
- }
- resultCode = CARD_NOT_SUPPORTED;
- }
- }
- } else {
- resultCode = TERMINAL_NOT_PRESENT;
- }
- } else {
- resultCode = PC_SC_NOT_SUPPORTED;
- }
- }
-
- public synchronized SignatureCard getSignatureCard(Locale locale) {
- if (signatureCard != null) {
- signatureCard.setLocale(locale);
- }
- return signatureCard;
- }
-
- public int getResultCode() {
- return resultCode;
- }
-
- public static String toString(byte[] b) {
- StringBuffer sb = new StringBuffer();
- sb.append('[');
- if (b != null && b.length > 0) {
- sb.append(Integer.toHexString((b[0] & 240) >> 4));
- sb.append(Integer.toHexString(b[0] & 15));
- for (int i = 1; i < b.length; i++) {
- sb.append((i % 32 == 0) ? '\n' : ':');
- sb.append(Integer.toHexString((b[i] & 240) >> 4));
- sb.append(Integer.toHexString(b[i] & 15));
- }
- }
- sb.append(']');
- return sb.toString();
- }
-
- public static boolean isUseSWCard() {
- return useSWCard;
- }
-
- public static void setUseSWCard(boolean useSWCard) {
- SMCCHelper.useSWCard = useSWCard;
- }
-}
+package at.gv.egiz.smcc.util; + +import java.util.Locale; +import java.util.Map; + +import javax.smartcardio.Card; +import javax.smartcardio.CardTerminal; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.CardNotSupportedException; +import at.gv.egiz.smcc.SignatureCard; +import at.gv.egiz.smcc.SignatureCardFactory; + +public class SMCCHelper { + + public final static int NO_CARD = 0; + public final static int PC_SC_NOT_SUPPORTED = 1; + public final static int TERMINAL_NOT_PRESENT = 2; + public final static int CARD_NOT_SUPPORTED = 3; + public final static int CARD_FOUND = 4; + + private final Logger log = LoggerFactory.getLogger(SMCCHelper.class); + + protected SmartCardIO smartCardIO = new SmartCardIO(); + protected int resultCode = NO_CARD; + protected SignatureCard signatureCard = null; + protected static boolean useSWCard = false; + + public SMCCHelper() { + update(); + } + + public synchronized void update() { + update(-1); + } + + public synchronized void update(int sleep) { + SignatureCardFactory factory = SignatureCardFactory.getInstance(); + if (useSWCard) { + try { + signatureCard = factory.createSignatureCard(null, null); + resultCode = CARD_FOUND; + } catch (CardNotSupportedException e) { + resultCode = CARD_NOT_SUPPORTED; + signatureCard = null; + } + return; + } + signatureCard = null; + resultCode = NO_CARD; + // find pcsc support + if (smartCardIO.isPCSCSupported()) { + // find supported card + if (smartCardIO.isTerminalPresent()) { + Map<CardTerminal, Card> newCards = null; + if (sleep > 0) { + smartCardIO.waitForInserted(sleep); + + } + newCards = smartCardIO.getCards(); + for (CardTerminal cardTerminal : newCards.keySet()) { + try { + Card c = newCards.get(cardTerminal); + if (c == null) { + throw new CardNotSupportedException(); + } + signatureCard = factory.createSignatureCard(c, cardTerminal); + if (log.isTraceEnabled()) { + Object[] args = { signatureCard, cardTerminal.getName(), + toString(newCards.get(cardTerminal).getATR().getBytes()) }; + log.trace("Found supported card ({}) in terminal '{}', ATR = {}.", args); + } + resultCode = CARD_FOUND; + break; + + } catch (CardNotSupportedException e) { + Card c = newCards.get(cardTerminal); + if (c != null) { + Object[] args = { cardTerminal.getName(), + toString(c.getATR().getBytes()) }; + log.info("Found unsupported card in terminal '{}', ATR = {}.", + args); + } else { + log.info("Found unsupported card in terminal '{}' without ATR.", + cardTerminal.getName()); + } + resultCode = CARD_NOT_SUPPORTED; + } + } + } else { + resultCode = TERMINAL_NOT_PRESENT; + } + } else { + resultCode = PC_SC_NOT_SUPPORTED; + } + } + + public synchronized SignatureCard getSignatureCard(Locale locale) { + if (signatureCard != null) { + signatureCard.setLocale(locale); + } + return signatureCard; + } + + public int getResultCode() { + return resultCode; + } + + public static String toString(byte[] b) { + StringBuffer sb = new StringBuffer(); + sb.append('['); + if (b != null && b.length > 0) { + sb.append(Integer.toHexString((b[0] & 240) >> 4)); + sb.append(Integer.toHexString(b[0] & 15)); + for (int i = 1; i < b.length; i++) { + sb.append((i % 32 == 0) ? '\n' : ':'); + sb.append(Integer.toHexString((b[i] & 240) >> 4)); + sb.append(Integer.toHexString(b[i] & 15)); + } + } + sb.append(']'); + return sb.toString(); + } + + public static boolean isUseSWCard() { + return useSWCard; + } + + public static void setUseSWCard(boolean useSWCard) { + SMCCHelper.useSWCard = useSWCard; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java b/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java index b1866894..14ee7549 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java @@ -14,191 +14,191 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package at.gv.egiz.smcc.util;
-
+package at.gv.egiz.smcc.util; + import java.security.NoSuchAlgorithmException; -import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.smartcardio.Card;
-import javax.smartcardio.CardException;
-import javax.smartcardio.CardTerminal;
-import javax.smartcardio.CardTerminals;
-import javax.smartcardio.TerminalFactory;
-import javax.smartcardio.CardTerminals.State;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- *
- * @author mcentner
- */
-public class SmartCardIO {
-
- private static final int STATE_INITIALIZED = 1;
-
- private static final int STATE_TERMINAL_FACTORY = 2;
-
- private static final int STATE_TERMINALS = 3;
-
- private static Log log = LogFactory.getLog(SmartCardIO.class);
-
- final Map<CardTerminal, Card> terminalCard_ = new HashMap<CardTerminal, Card>();
-
- int state_ = STATE_INITIALIZED;
-
- TerminalFactory terminalFactory_ = null;
-
- CardTerminals cardTerminals_;
-
- private void updateTerminalFactory() {
+import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.smartcardio.Card; +import javax.smartcardio.CardException; +import javax.smartcardio.CardTerminal; +import javax.smartcardio.CardTerminals; +import javax.smartcardio.TerminalFactory; +import javax.smartcardio.CardTerminals.State; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author mcentner + */ +public class SmartCardIO { + + private static final int STATE_INITIALIZED = 1; + + private static final int STATE_TERMINAL_FACTORY = 2; + + private static final int STATE_TERMINALS = 3; + + private final Logger log = LoggerFactory.getLogger(SmartCardIO.class); + + final Map<CardTerminal, Card> terminalCard_ = new HashMap<CardTerminal, Card>(); + + int state_ = STATE_INITIALIZED; + + TerminalFactory terminalFactory_ = null; + + CardTerminals cardTerminals_; + + private void updateTerminalFactory() { TerminalFactory terminalFactory; try { terminalFactory = TerminalFactory.getInstance("PC/SC", null); } catch (NoSuchAlgorithmException e) { log.info("Failed to get TerminalFactory of type 'PC/SC'.", e); terminalFactory = TerminalFactory.getDefault(); - }
- log.debug("TerminalFactory : " + terminalFactory);
- if ("PC/SC".equals(terminalFactory.getType())) {
- terminalFactory_ = terminalFactory;
- }
- if(state_ < STATE_TERMINAL_FACTORY) {
- state_ = STATE_TERMINAL_FACTORY;
- }
- }
-
- public boolean isPCSCSupported() {
- if(state_ < STATE_TERMINAL_FACTORY) {
- updateTerminalFactory();
- }
- return terminalFactory_ != null;
- }
-
- private void updateCardTerminals() {
- if(terminalFactory_ != null) {
- cardTerminals_ = terminalFactory_.terminals();
- }
- log.debug("CardTerminals : " + cardTerminals_);
- if (state_ < STATE_TERMINALS) {
- state_ = STATE_TERMINALS;
- }
- }
-
- public CardTerminals getCardTerminals() {
- if(state_ < STATE_TERMINAL_FACTORY) {
- updateTerminalFactory();
- }
- if(state_ < STATE_TERMINALS) {
- updateCardTerminals();
- }
- return cardTerminals_;
- }
-
- public boolean isTerminalPresent() {
- CardTerminals cardTerminals = getCardTerminals();
- if (cardTerminals != null) {
- List<CardTerminal> terminals = null;
- try {
- terminals = cardTerminals.list(State.ALL);
-
- // logging
- if(log.isInfoEnabled()) {
- if (terminals == null || terminals.isEmpty()) {
- log.info("No card terminal found.");
- } else {
- StringBuffer msg = new StringBuffer();
- msg.append("Found " + terminals.size() + " card terminal(s):");
- for (CardTerminal terminal : terminals) {
- msg.append("\n " + terminal.getName());
- }
- log.info(msg.toString());
- }
- }
-
- return terminals != null && !terminals.isEmpty();
- } catch (CardException e) {
- log.info("Failed to list card terminals.", e);
- return false;
- }
- } else {
- return false;
- }
- }
-
- private Map<CardTerminal, Card> updateCards() {
-
- // clear card references if removed
- try {
- log.trace("terminals.list(State.CARD_REMOVAL)");
- for (CardTerminal terminal : cardTerminals_.list(CardTerminals.State.CARD_REMOVAL)) {
- Card card = terminalCard_.remove(terminal);
- log.trace("card removed : " + card);
- }
- } catch (CardException e) {
- log.debug(e);
- }
-
- // check inserted cards
- Map<CardTerminal, Card> newCards = new HashMap<CardTerminal, Card>();
- try {
- log.trace("terminals.list(State.CARD_INSERTION)");
- for (CardTerminal terminal : cardTerminals_.list(CardTerminals.State.CARD_INSERTION)) {
-
- Card card = null;
+ } + log.debug("TerminalFactory : {}.", terminalFactory); + if ("PC/SC".equals(terminalFactory.getType())) { + terminalFactory_ = terminalFactory; + } + if(state_ < STATE_TERMINAL_FACTORY) { + state_ = STATE_TERMINAL_FACTORY; + } + } + + public boolean isPCSCSupported() { + if(state_ < STATE_TERMINAL_FACTORY) { + updateTerminalFactory(); + } + return terminalFactory_ != null; + } + + private void updateCardTerminals() { + if(terminalFactory_ != null) { + cardTerminals_ = terminalFactory_.terminals(); + } + log.debug("CardTerminals : {}.", cardTerminals_); + if (state_ < STATE_TERMINALS) { + state_ = STATE_TERMINALS; + } + } + + public CardTerminals getCardTerminals() { + if(state_ < STATE_TERMINAL_FACTORY) { + updateTerminalFactory(); + } + if(state_ < STATE_TERMINALS) { + updateCardTerminals(); + } + return cardTerminals_; + } + + public boolean isTerminalPresent() { + CardTerminals cardTerminals = getCardTerminals(); + if (cardTerminals != null) { + List<CardTerminal> terminals = null; + try { + terminals = cardTerminals.list(State.ALL); + + // logging + if(log.isInfoEnabled()) { + if (terminals == null || terminals.isEmpty()) { + log.info("No card terminal found."); + } else { + StringBuffer msg = new StringBuffer(); + msg.append("Found " + terminals.size() + " card terminal(s):"); + for (CardTerminal terminal : terminals) { + msg.append("\n " + terminal.getName()); + } + log.info(msg.toString()); + } + } + + return terminals != null && !terminals.isEmpty(); + } catch (CardException e) { + log.info("Failed to list card terminals.", e); + return false; + } + } else { + return false; + } + } + + private Map<CardTerminal, Card> updateCards() { + + // clear card references if removed + try { + log.trace("terminals.list(State.CARD_REMOVAL)"); + for (CardTerminal terminal : cardTerminals_.list(CardTerminals.State.CARD_REMOVAL)) { + Card card = terminalCard_.remove(terminal); + log.trace("card removed : {}", card); + } + } catch (CardException e) { + log.debug("Failed to list terminals.", e); + } + + // check inserted cards + Map<CardTerminal, Card> newCards = new HashMap<CardTerminal, Card>(); + try { + log.trace("terminals.list(State.CARD_INSERTION)"); + for (CardTerminal terminal : cardTerminals_.list(CardTerminals.State.CARD_INSERTION)) { + + Card card = null; try { log.trace("Trying to connect to card."); - // try to connect to card
- card = terminal.connect("*");
- } catch (CardException e) {
- log.trace("Failed to connect to card.", e);
- }
-
- // have we seen this card before?
- if (terminalCard_.put(terminal, card) == null) {
- terminalCard_.put(terminal, card);
- newCards.put(terminal, card);
- log.trace("terminal '" + terminal + "' card inserted : " + card);
- }
- }
- } catch (CardException e) {
- log.debug(e);
- }
- return newCards;
-
- }
-
- public Map<CardTerminal, Card> getCards() {
- if(state_ < STATE_TERMINAL_FACTORY) {
- updateTerminalFactory();
- }
- if(state_ < STATE_TERMINALS) {
- updateCardTerminals();
- }
- updateCards();
- Map<CardTerminal, Card> terminalCard = new HashMap<CardTerminal, Card>();
- terminalCard.putAll(terminalCard_);
- return Collections.unmodifiableMap(terminalCard);
- }
-
- public Map<CardTerminal, Card> waitForInserted(int timeout) {
- if(state_ < STATE_TERMINAL_FACTORY) {
- updateTerminalFactory();
- }
- if(state_ < STATE_TERMINALS) {
- updateCardTerminals();
- }
- try {
- // just waiting for a short period of time to allow for abort
- cardTerminals_.waitForChange(timeout);
- } catch (CardException e) {
- log.debug("CardTerminals.waitForChange(" + timeout + ") failed.", e);
- }
- Map<CardTerminal, Card> newCards = new HashMap<CardTerminal, Card>();
- newCards.putAll(updateCards());
- return Collections.unmodifiableMap(newCards);
- }
-}
\ No newline at end of file + // try to connect to card + card = terminal.connect("*"); + } catch (CardException e) { + log.trace("Failed to connect to card.", e); + } + + // have we seen this card before? + if (terminalCard_.put(terminal, card) == null) { + terminalCard_.put(terminal, card); + newCards.put(terminal, card); + log.trace("terminal '{}' card inserted : {}", terminal, card); + } + } + } catch (CardException e) { + log.debug("Failed to list cards.", e); + } + return newCards; + + } + + public Map<CardTerminal, Card> getCards() { + if(state_ < STATE_TERMINAL_FACTORY) { + updateTerminalFactory(); + } + if(state_ < STATE_TERMINALS) { + updateCardTerminals(); + } + updateCards(); + Map<CardTerminal, Card> terminalCard = new HashMap<CardTerminal, Card>(); + terminalCard.putAll(terminalCard_); + return Collections.unmodifiableMap(terminalCard); + } + + public Map<CardTerminal, Card> waitForInserted(int timeout) { + if(state_ < STATE_TERMINAL_FACTORY) { + updateTerminalFactory(); + } + if(state_ < STATE_TERMINALS) { + updateCardTerminals(); + } + try { + // just waiting for a short period of time to allow for abort + cardTerminals_.waitForChange(timeout); + } catch (CardException e) { + log.debug("CardTerminals.waitForChange({}) failed.", timeout, e); + } + Map<CardTerminal, Card> newCards = new HashMap<CardTerminal, Card>(); + newCards.putAll(updateCards()); + return Collections.unmodifiableMap(newCards); + } +} |