From 3da4655d011dfc2f04f9e4ac28b38aee42d01bc0 Mon Sep 17 00:00:00 2001 From: clemenso Date: Tue, 5 Jan 2010 10:06:47 +0000 Subject: Features [#437] Handle pinpad [64:03] response apdu correctly [#445] pin entry feedback for VERIFY_PIN_START/FINISH [#471] Provide SecureViewer Link before Pinpad PinEntry timeout starts Bugs [#479] PIN Managment Applet allows unmatching new pin and pin confirmation [#480] PIN Management displays blocked PINs as ACTIVE [#486] Not possible to select 3 times in series the same item from signedReferencesList for display in secureViewer [#506] change pin dialog (gui) issues [#508] e-card G3 PIN activation (with TransportPIN) not supported [#509] closing secure viewer window (WINDOW_CLOSING) leaves "signature data is displayed in viewer" dialog in applet git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@565 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java | 44 +- .../at/gv/egiz/smcc/AbstractSignatureCard.java | 14 +- smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java | 11 +- .../java/at/gv/egiz/smcc/ChangePINProvider.java | 36 -- smcc/src/main/java/at/gv/egiz/smcc/ITCard.java | 11 +- .../at/gv/egiz/smcc/PINConfirmationException.java | 19 - .../java/at/gv/egiz/smcc/PINFormatException.java | 19 - .../java/at/gv/egiz/smcc/PINMgmtSignatureCard.java | 11 +- .../src/main/java/at/gv/egiz/smcc/PINProvider.java | 45 -- .../at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java | 38 ++ .../src/main/java/at/gv/egiz/smcc/STARCOSCard.java | 208 +++--- smcc/src/main/java/at/gv/egiz/smcc/SWCard.java | 106 +--- .../main/java/at/gv/egiz/smcc/SignatureCard.java | 9 +- .../java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java | 36 ++ .../at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java | 48 ++ .../main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java | 42 ++ .../java/at/gv/egiz/smcc/pin/gui/PINProvider.java | 49 ++ .../java/at/gv/egiz/smcc/reader/CardReader.java | 92 +++ .../at/gv/egiz/smcc/reader/DefaultCardReader.java | 106 ++++ .../at/gv/egiz/smcc/reader/PinpadCardReader.java | 703 +++++++++++++++++++++ .../java/at/gv/egiz/smcc/reader/ReaderFactory.java | 128 ++++ .../test/java/at/gv/egiz/smcc/AbstractAppl.java | 1 + smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java | 14 +- smcc/src/test/java/at/gv/egiz/smcc/CardTest.java | 171 +---- smcc/src/test/java/at/gv/egiz/smcc/PIN.java | 10 +- .../test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java | 2 +- .../java/at/gv/egiz/smcc/acos/A03CardEmul.java | 7 +- .../java/at/gv/egiz/smcc/acos/A03CardTest.java | 9 +- .../java/at/gv/egiz/smcc/acos/A04CardEmul.java | 7 +- .../java/at/gv/egiz/smcc/acos/A04CardTest.java | 12 +- .../java/at/gv/egiz/smcc/acos/ACOSApplDEC.java | 2 +- .../java/at/gv/egiz/smcc/acos/ACOSApplSIG.java | 2 +- .../java/at/gv/egiz/smcc/acos/ACOSCardTest.java | 21 +- .../egiz/smcc/pin/gui/CancelChangePINProvider.java | 39 ++ .../at/gv/egiz/smcc/pin/gui/CancelPINProvider.java | 29 + .../at/gv/egiz/smcc/pin/gui/ChangePINProvider.java | 49 ++ .../at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java | 68 ++ .../java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java | 48 ++ .../gv/egiz/smcc/pin/gui/InterruptPINProvider.java | 34 + .../smcc/pin/gui/InvalidChangePINProvider.java | 56 ++ .../gv/egiz/smcc/pin/gui/InvalidPINProvider.java | 48 ++ .../gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java | 43 ++ .../java/at/gv/egiz/smcc/starcos/STARCOSAppl.java | 23 - .../starcos/STARCOSApplGewoehnlicheSignatur.java | 27 +- .../gv/egiz/smcc/starcos/STARCOSApplInfobox.java | 5 + .../smcc/starcos/STARCOSApplSichereSignatur.java | 36 +- .../egiz/smcc/starcos/STARCOSCardChannelEmul.java | 105 ++- .../at/gv/egiz/smcc/starcos/STARCOSCardEmul.java | 24 +- .../at/gv/egiz/smcc/starcos/STARCOSCardTest.java | 132 ++-- .../smcc/starcos/STARCOSG3CardChannelEmul.java | 46 ++ .../at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java | 57 ++ .../at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java | 119 ++++ 52 files changed, 2337 insertions(+), 684 deletions(-) delete mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java delete mode 100644 smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java (limited to 'smcc/src') 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 1ed5a177..b8cdb208 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -16,6 +16,8 @@ */ package at.gv.egiz.smcc; +import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; +import at.gv.egiz.smcc.pin.gui.PINGUI; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -79,10 +81,16 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC public static final byte KID_PIN_SIG = (byte) 0x81; + public static final byte KID_PUK_SIG = (byte) 0x83; + public static final byte KID_PIN_DEC = (byte) 0x81; + public static final byte KID_PUK_DEC = (byte) 0x82; + public static final byte KID_PIN_INF = (byte) 0x83; + public static final byte KID_PUK_INF = (byte) 0x84; + public static final byte[] DST_SIG = new byte[] { (byte) 0x84, (byte) 0x01, // tag // , // length @@ -217,7 +225,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC @Override @Exclusive - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + public byte[] getInfobox(String infobox, PINGUI provider, String domainId) throws SignatureCardException, InterruptedException { if ("IdentityLink".equals(infobox)) { @@ -233,7 +241,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } - protected byte[] getIdentityLinkV1(PINProvider provider, String domainId) + protected byte[] getIdentityLinkV1(PINGUI provider, String domainId) throws SignatureCardException, InterruptedException { try { @@ -262,7 +270,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } - protected byte[] getIdentityLinkV2(PINProvider provider, String domainId) + protected byte[] getIdentityLinkV2(PINGUI provider, String domainId) throws SignatureCardException, InterruptedException { try { @@ -388,7 +396,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC @Override @Exclusive public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException { + PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException { ByteArrayOutputStream dst = new ByteArrayOutputStream(); // key ID @@ -487,7 +495,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider) */ @Override - public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider) + public void verifyPIN(PINSpec pinSpec, PINGUI pinProvider) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { @@ -509,7 +517,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.ChangePINProvider) */ @Override - public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) + public void changePIN(PINSpec pinSpec, ModifyPINGUI pinProvider) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { @@ -528,7 +536,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } @Override - public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) + public void activatePIN(PINSpec pinSpec, ModifyPINGUI pinGUI) throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException { log.error("ACTIVATE PIN not supported by ACOS"); @@ -536,7 +544,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } @Override - public void unblockPIN(PINSpec pinSpec, PINProvider pinProvider) + public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pinGUI) throws CancelledException, SignatureCardException, InterruptedException { throw new SignatureCardException("Unblock PIN not supported."); } @@ -570,10 +578,8 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC // PROTECTED METHODS (assume exclusive card access) //////////////////////////////////////////////////////////////////////// - protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINProvider provider) - throws InterruptedException, LockedException, NotActivatedException, - TimeoutException, PINFormatException, PINOperationAbortedException, - SignatureCardException, CardException { + protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINGUI provider) + throws InterruptedException, CardException, SignatureCardException { int retries = -1; do { @@ -581,10 +587,8 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } while (retries > 0); } - protected void changePINLoop(CardChannel channel, PINSpec spec, ChangePINProvider provider) - throws InterruptedException, LockedException, NotActivatedException, - TimeoutException, PINFormatException, PINOperationAbortedException, - SignatureCardException, CardException { + protected void changePINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider) + throws InterruptedException, CardException, SignatureCardException { int retries = -1; do { @@ -593,7 +597,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } protected int verifyPIN(CardChannel channel, PINSpec pinSpec, - PINProvider provider, int retries) throws InterruptedException, CardException, SignatureCardException { + PINGUI provider, int retries) throws InterruptedException, CardException, SignatureCardException { VerifyAPDUSpec apduSpec = new VerifyAPDUSpec( new byte[] { @@ -602,7 +606,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }, 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8); - ResponseAPDU resp = reader.verify(channel, apduSpec, pinSpec, provider, retries); + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); if (resp.getSW() == 0x9000) { return -1; @@ -625,7 +629,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC } protected int changePIN(CardChannel channel, PINSpec pinSpec, - ChangePINProvider pinProvider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException { + ModifyPINGUI pinProvider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException { ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec( new byte[] { @@ -639,7 +643,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC - ResponseAPDU resp = reader.modify(channel, apduSpec, pinSpec, pinProvider, retries); + ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinSpec, retries); if (resp.getSW() == 0x9000) { return -1; 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 54b4c7fe..fcb94fc6 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -16,6 +16,8 @@ */ 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; @@ -29,9 +31,6 @@ import javax.smartcardio.CardTerminal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import at.gv.egiz.smcc.ccid.CCID; -import at.gv.egiz.smcc.ccid.ReaderFactory; - public abstract class AbstractSignatureCard implements SignatureCard { private static Log log = LogFactory.getLog(AbstractSignatureCard.class); @@ -45,7 +44,7 @@ public abstract class AbstractSignatureCard implements SignatureCard { private Card card_; - protected CCID reader; + protected CardReader reader; protected AbstractSignatureCard(String resourceBundleName) { this.resourceBundleName = resourceBundleName; @@ -68,7 +67,7 @@ public abstract class AbstractSignatureCard implements SignatureCard { @Override public void init(Card card, CardTerminal cardTerminal) { this.card_ = card; - this.reader = ReaderFactory.getInstance().getReader(card, cardTerminal); + this.reader = ReaderFactory.getReader(card, cardTerminal); } @Override @@ -80,11 +79,6 @@ public abstract class AbstractSignatureCard implements SignatureCard { return new LogCardChannel(card_.getBasicChannel()); } - @Override - public CCID getReader() { - return reader; - } - @Override public void setLocale(Locale locale) { if (locale == null) { 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 e02a55d4..41358bb5 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java @@ -18,6 +18,7 @@ package at.gv.egiz.smcc; +import at.gv.egiz.smcc.pin.gui.PINGUI; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; @@ -110,7 +111,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { @Override @Exclusive - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + public byte[] getInfobox(String infobox, PINGUI provider, String domainId) throws SignatureCardException, InterruptedException { throw new IllegalArgumentException("Infobox '" + infobox @@ -120,7 +121,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { @Override @Exclusive public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException { + PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException { if (KeyboxName.SECURE_SIGNATURE_KEYPAIR != keyboxName) { throw new SignatureCardException("Card does not support key " + keyboxName + "."); @@ -176,7 +177,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { } protected void verifyPINLoop(CardChannel channel, PINSpec spec, - PINProvider provider) throws LockedException, NotActivatedException, + PINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { int retries = -1; //verifyPIN(channel, spec, null, -1); @@ -186,7 +187,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { } protected int verifyPIN(CardChannel channel, PINSpec pinSpec, - PINProvider provider, int retries) throws SignatureCardException, + PINGUI provider, int retries) throws SignatureCardException, LockedException, NotActivatedException, InterruptedException, CardException { @@ -197,7 +198,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard { (byte) 0xff, (byte) 0xff, (byte) 0xff }, 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4); - ResponseAPDU resp = reader.verify(channel, apduSpec, pinSpec, provider, retries); + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); if (resp.getSW() == 0x9000) { return -1; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java deleted file mode 100644 index 41010551..00000000 --- a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java +++ /dev/null @@ -1,36 +0,0 @@ -/* -* Copyright 2008 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; - -/** - * - * @author Clemens Orthacker - */ -public interface ChangePINProvider extends PINProvider { - - /** - * - * @param spec - * @param retries - * @return null if no old value for this pin - * @throws at.gv.egiz.smcc.CancelledException if cancelled by user - * @throws java.lang.InterruptedException - */ - public char[] provideOldPIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException; - -} 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 831a1f9b..64389190 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java @@ -17,6 +17,7 @@ package at.gv.egiz.smcc; +import at.gv.egiz.smcc.pin.gui.PINGUI; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -96,7 +97,7 @@ public class ITCard extends AbstractSignatureCard { @Override @Exclusive - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + public byte[] getInfobox(String infobox, PINGUI provider, String domainId) throws SignatureCardException, InterruptedException { throw new IllegalArgumentException("Infobox '" + infobox @@ -106,7 +107,7 @@ public class ITCard extends AbstractSignatureCard { @Override @Exclusive public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINProvider provider, String alg) throws SignatureCardException, + PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException { if (KeyboxName.SECURE_SIGNATURE_KEYPAIR != keyboxName) { @@ -159,7 +160,7 @@ public class ITCard extends AbstractSignatureCard { } protected void verifyPINLoop(CardChannel channel, PINSpec spec, - PINProvider provider) throws LockedException, NotActivatedException, + PINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { int retries = -1; @@ -169,7 +170,7 @@ public class ITCard extends AbstractSignatureCard { } protected int verifyPIN(CardChannel channel, PINSpec pinSpec, - PINProvider provider, int retries) throws SignatureCardException, + PINGUI provider, int retries) throws SignatureCardException, LockedException, NotActivatedException, InterruptedException, CardException { @@ -180,7 +181,7 @@ public class ITCard extends AbstractSignatureCard { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8); - ResponseAPDU resp = reader.verify(channel, apduSpec, pinSpec, provider, retries); + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); if (resp.getSW() == 0x9000) { return -2; 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 eaf38435..24dfa53c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java @@ -23,23 +23,4 @@ package at.gv.egiz.smcc; * @author Clemens Orthacker */ public class PINConfirmationException extends SignatureCardException { - - private static final long serialVersionUID = 1L; - - public PINConfirmationException() { - super(); - } - - public PINConfirmationException(String message, Throwable cause) { - super(message, cause); - } - - public PINConfirmationException(String message) { - super(message); - } - - public PINConfirmationException(Throwable cause) { - super(cause); - } - } 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 774fcdf5..721c63e2 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java @@ -23,23 +23,4 @@ package at.gv.egiz.smcc; * @author Clemens Orthacker */ public class PINFormatException extends SignatureCardException { - - private static final long serialVersionUID = 1L; - - public PINFormatException() { - super(); - } - - public PINFormatException(String message, Throwable cause) { - super(message, cause); - } - - public PINFormatException(String message) { - super(message); - } - - public PINFormatException(Throwable cause) { - super(cause); - } - } 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 53738612..5091c10f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java @@ -16,6 +16,9 @@ */ 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 { @@ -26,16 +29,16 @@ public interface PINMgmtSignatureCard extends SignatureCard { public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException; - public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider) + public void verifyPIN(PINSpec pinSpec, PINGUI pinGUI) throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException; - public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) + public void changePIN(PINSpec pinSpec, ModifyPINGUI changePINGUI) throws LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException; - public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) + public void activatePIN(PINSpec pinSpec, ModifyPINGUI activatePINGUI) throws CancelledException, SignatureCardException, InterruptedException; - public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider) + public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pukGUI) throws CancelledException, SignatureCardException, InterruptedException; } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java deleted file mode 100644 index 5c294b5b..00000000 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -/* -* Copyright 2008 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; - -/** - * The number of retries is not fixed and there is no way (?) to obtain this value. - * A PINProvider should therefore maintain an internal retry counter or flag - * to decide whether or not to warn the user (num retries passed in providePIN). - * - * Therefore PINProvider objects should not be reused. - * - * (ACOS: reload counter: between 0 and 15, where 15 meens deactivated) - * - * @author Clemens Orthacker - */ -public interface PINProvider { - - /** - * - * @param spec - * @param retries num of remaining retries or -1 if unknown - * (a positive value does not necessarily signify that there was - * already an unsuccessful PIN verification) - * @return pin != null - * @throws at.gv.egiz.smcc.CancelledException - * @throws java.lang.InterruptedException - */ - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException; - -} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java new file mode 100644 index 00000000..7e71eb7e --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java @@ -0,0 +1,38 @@ +/* +* Copyright 2008 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; + +public class ResetRetryCounterAPDUSpec extends ChangeReferenceDataAPDUSpec { + + /** + * @param apdu + * @param pukPosition + * @param pukFormat + * @param pukLength + * @param pukLengthSize + * @param pukLengthPos + * @param pinInsertionOffsetNew + */ + public ResetRetryCounterAPDUSpec(byte[] apdu, int pukPosition, + int pukFormat, int pukLength, int pukLengthSize, int pukLengthPos, + int pinInsertionOffsetNew) { + super(apdu, pukPosition, pukFormat, pukLength, pukLengthSize, pukLengthPos); + this.pinInsertionOffsetNew = pinInsertionOffsetNew; + } + + +} 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 79a4cc69..ad05352f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -17,6 +17,8 @@ package at.gv.egiz.smcc; +import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; +import at.gv.egiz.smcc.pin.gui.PINGUI; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -225,7 +227,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu @Override @Exclusive - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) throws SignatureCardException, InterruptedException { try { @@ -243,7 +245,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu try { return ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30); } catch (SecurityStatusNotSatisfiedException e) { - verifyPINLoop(channel, spec, provider); + verifyPINLoop(channel, spec, pinGUI); } } @@ -301,7 +303,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu @Override @Exclusive public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException { + PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException { ByteArrayOutputStream dst = new ByteArrayOutputStream(); byte[] ht = null; @@ -431,7 +433,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu */ @Override @Exclusive - public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider) + public void verifyPIN(PINSpec pinSpec, PINGUI pinProvider) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { @@ -442,12 +444,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu // SELECT application execSELECT_AID(channel, pinSpec.getContextAID()); } - log.debug("*** verifyPIN loop"); verifyPINLoop(channel, pinSpec, pinProvider); -// log.debug("*** verifyPIN 0"); -// int retries = verifyPIN(channel, pinSpec, null, 0); -// log.debug("*** verifyPIN " + retries + " tries"); -// verifyPIN(channel, pinSpec, pinProvider, retries); } catch (CardException e) { log.info("Failed to verify PIN.", e); throw new SignatureCardException("Failed to verify PIN.", e); @@ -460,7 +457,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu */ @Override @Exclusive - public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) + public void changePIN(PINSpec pinSpec, ModifyPINGUI pinGUI) throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { @@ -471,9 +468,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu // SELECT application execSELECT_AID(channel, pinSpec.getContextAID()); } - changePINLoop(channel, pinSpec, pinProvider); -// int retries = verifyPIN(channel, pinSpec, null, 0); -// changePIN(channel, pinSpec, pinProvider, retries); + changePINLoop(channel, pinSpec, pinGUI); } catch (CardException e) { log.info("Failed to change PIN.", e); throw new SignatureCardException("Failed to change PIN.", e); @@ -486,7 +481,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu */ @Override @Exclusive - public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) + public void activatePIN(PINSpec pinSpec, ModifyPINGUI activatePINGUI) throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException { @@ -497,7 +492,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu // SELECT application execSELECT_AID(channel, pinSpec.getContextAID()); } - activatePIN(channel, pinSpec, pinProvider); + activatePIN(channel, pinSpec, activatePINGUI); } catch (CardException e) { log.info("Failed to activate PIN.", e); throw new SignatureCardException("Failed to activate PIN.", e); @@ -509,9 +504,16 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu * @see at.gv.egiz.smcc.PINMgmtSignatureCard#unblockPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider) */ @Override - public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider) + public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pukProvider) throws CancelledException, SignatureCardException, InterruptedException { - throw new SignatureCardException("Unblock PIN is not supported."); + CardChannel channel = getCardChannel(); + + try { + unblockPINLoop(channel, pinSpec, pukProvider); + } catch (CardException e) { + log.info("Failed to activate PIN.", e); + throw new SignatureCardException("Failed to activate PIN.", e); + } } @Override @@ -574,7 +576,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu // PROTECTED METHODS (assume exclusive card access) //////////////////////////////////////////////////////////////////////// - protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINProvider provider) + protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { @@ -584,7 +586,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } while (retries > 0); } - protected void changePINLoop(CardChannel channel, PINSpec spec, ChangePINProvider provider) + protected void changePINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider) throws LockedException, NotActivatedException, SignatureCardException, InterruptedException, CardException { @@ -594,8 +596,19 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu } while (retries > 0); } + protected void unblockPINLoop(CardChannel channel, PINSpec spec, 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); + } while (retries > 0); + } + protected int verifyPIN(CardChannel channel, PINSpec pinSpec, - PINProvider provider, int retries) throws SignatureCardException, + PINGUI provider, int retries) throws SignatureCardException, LockedException, NotActivatedException, InterruptedException, CardException { @@ -608,108 +621,135 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu ResponseAPDU resp; if (provider != null) { - resp = reader.verify(channel, apduSpec, pinSpec, provider, retries); + resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); } else { resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00, pinSpec.getKID())); } - + + if (resp.getSW() == 0x9000) { return -1; - } - if (resp.getSW() == 0x63c0) { - // returned by the 'short' VERIFY + } else if (resp.getSW() == 0x6983 || resp.getSW() == 0x63c0) { + // authentication method blocked (0x63c0 returned by 'short' VERIFY) throw new LockedException(); - } - if (resp.getSW() >> 4 == 0x63c) { - return 0x0f & resp.getSW(); - } - - switch (resp.getSW()) { - case 0x6983: - // authentication method blocked - // returned by the 'long' VERIFY - throw new LockedException(); - case 0x6984: - // reference data not usable + } else if (resp.getSW() == 0x6984 || resp.getSW() == 0x6985) { + // reference data not usable; conditions of use not satisfied throw new NotActivatedException(); - case 0x6985: - // conditions of use not satisfied + } else if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } else if (version > 1.2 && resp.getSW() == 0x6400) { + log.warn("cannot query pin status prior to card activation"); throw new NotActivatedException(); - - default: + } else { String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW()); log.info(msg); throw new SignatureCardException(msg); } - } protected int changePIN(CardChannel channel, PINSpec pinSpec, - ChangePINProvider pinProvider, int retries) throws CancelledException, + 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) 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 }, + + ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec( + new byte[] { + (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.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, pinSpec, pinProvider, retries); - + + ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinSpec, retries); + if (resp.getSW() == 0x9000) { return -1; - } - if (resp.getSW() >> 4 == 0x63c) { - return 0x0f & resp.getSW(); - } - - switch (resp.getSW()) { - case 0x6983: + } else if (resp.getSW() == 0x6983) { // authentication method blocked throw new LockedException(); - - default: + } else if (resp.getSW() == 0x6984) { + throw new NotActivatedException(); + } else if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } else { String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW()); log.info(msg); throw new SignatureCardException(msg); } - - } protected int activatePIN(CardChannel channel, PINSpec pinSpec, - PINProvider provider) throws SignatureCardException, + ModifyPINGUI provider) throws SignatureCardException, InterruptedException, CardException { - NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec( + ResponseAPDU resp; + if (version < 1.2) { + NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec( + new byte[] { + (byte) 0x00, (byte) 0x24, (byte) 0x01, pinSpec.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); + } else { + NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec( + new byte[] { + (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.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); + } + + if (resp.getSW() == 0x9000) { + return -1; + } else { + String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW()); + log.info(msg); + throw new SignatureCardException(msg); + } + } + + protected int unblockPIN(CardChannel channel, PINSpec pinSpec, + ModifyPINGUI provider, int retries) throws SignatureCardException, + InterruptedException, CardException { + + if (version < 1.2) { + // would return 0x6982 (Security status not satisfied) + throw new SignatureCardException("RESET RETRY COUNTER is not supported by this card."); + } + + ResetRetryCounterAPDUSpec apduSpec = new ResetRetryCounterAPDUSpec( new byte[] { - (byte) 0x00, (byte) 0x24, (byte) 0x01, pinSpec.getKID(), (byte) 0x08, + (byte) 0x00, (byte) 0x2c, (byte) 0x00, pinSpec.getKID(), (byte) 0x10, (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 = reader.activate(channel, apduSpec, pinSpec, provider); - - switch (resp.getSW()) { - - case 0x9000: - return -1; + (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); - case 0x6983: - // authentication method blocked - throw new LockedException(); + ResponseAPDU resp = reader.modify(channel, apduSpec, provider, pinSpec, retries); - default: - String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW()); + if (resp.getSW() == 0x9000) { + return -1; + } else if (resp.getSW() == 0x6983) { + // PUK blocked + throw new LockedException(); + } else if (resp.getSW() == 0x6984) { + throw new NotActivatedException(); + } else if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } else { + String msg = "RESET RETRY COUNTER failed. SW=" + Integer.toHexString(resp.getSW()); log.info(msg); throw new SignatureCardException(msg); } - } - + protected void execSELECT_MF(CardChannel channel) throws CardException, SignatureCardException { ResponseAPDU resp = channel.transmit( new CommandAPDU(0x00, 0xA4, 0x00, 0x0C)); 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 670704d5..73c7faa8 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -40,15 +40,12 @@ import java.util.Enumeration; import java.util.Locale; import javax.smartcardio.Card; -import javax.smartcardio.CardChannel; -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 at.gv.egiz.smcc.ccid.CCID; +import at.gv.egiz.smcc.pin.gui.PINGUI; /** * @@ -280,7 +277,7 @@ public class SWCard implements SignatureCard { } - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) throws SignatureCardException { + public byte[] getInfobox(String infobox, PINGUI provider, String domainId) throws SignatureCardException { String fileName = getFileName(infobox + ".ibx"); FileInputStream file; @@ -309,7 +306,7 @@ public class SWCard implements SignatureCard { } @Override - public byte[] createSignature(InputStream input, KeyboxName keyboxName, PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException { + public byte[] createSignature(InputStream input, KeyboxName keyboxName, PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException { // KeyStore password char[] password = getPassword(keyboxName); @@ -396,101 +393,4 @@ public class SWCard implements SignatureCard { @Override public void reset() throws SignatureCardException { } - - @Override - public CCID getReader() { - return new CCID() { - - @Override - public boolean hasFeature(Byte feature) { - return false; - } - - @Override - public byte getbTimeOut() { - return 0; - } - - @Override - public byte getbTimeOut2() { - return 0; - } - - @Override - public byte getwPINMaxExtraDigitL() { - return 0x12; - } - - @Override - public byte getwPINMaxExtraDigitH() { - return 0x00; - } - - @Override - public byte getbEntryValidationCondition() { - return 0x02; - } - - @Override - public Card connect() { - return null; - } - - @Override - public String getName() { - return "Software CardReader"; - } - - @Override - public byte[] verifyPin(byte[] PIN_VERIFY) throws CardException { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public byte[] verifyPinDirect(byte[] PIN_VERIFY) throws CardException { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public byte[] modifyPin(byte[] PIN_MODIFY) throws CardException { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public byte[] modifyPinDirect(byte[] PIN_MODIFY) throws CardException { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void setDisablePinpad(boolean disable) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec, - PINSpec pinSpec, PINProvider provider, int retries) - throws CancelledException, InterruptedException, CardException, - SignatureCardException { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public ResponseAPDU activate(CardChannel channel, - NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec, - PINProvider provider) throws CancelledException, - InterruptedException, CardException, SignatureCardException { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResponseAPDU modify(CardChannel channel, - ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec, - ChangePINProvider provider, int retries) throws CancelledException, - InterruptedException, CardException, SignatureCardException { - // TODO Auto-generated method stub - return null; - } - }; - } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java index 3d56f97b..fa589b84 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java @@ -17,8 +17,7 @@ package at.gv.egiz.smcc; -import at.gv.egiz.smcc.ccid.CCID; - +import at.gv.egiz.smcc.pin.gui.PINGUI; import java.io.IOException; import java.io.InputStream; import java.util.Locale; @@ -99,7 +98,7 @@ public interface SignatureCard { * @throws SignatureCardException * @throws InterruptedException if applet is destroyed while in pin dialog */ - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) throws SignatureCardException, InterruptedException; /** @@ -114,9 +113,7 @@ public interface SignatureCard { * @throws IOException */ public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException; - - public CCID getReader(); + PINGUI pinGUI, String alg) throws SignatureCardException, InterruptedException, IOException; /** * Sets the local for evtl. required callbacks (e.g. PINSpec) 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 new file mode 100644 index 00000000..00dc2d0e --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java @@ -0,0 +1,36 @@ +/* +* Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + + +public interface ModifyPINGUI extends ModifyPINProvider { + + void modifyPINDirect(PINSpec spec, int retries) throws CancelledException, InterruptedException; + void finishDirect(); + + void enterCurrentPIN(PINSpec spec, int retries); + void enterNewPIN(PINSpec spec); + void confirmNewPIN(PINSpec spec); + void validKeyPressed(); + void correctionButtonPressed(); + void allKeysCleared(); + /** called prior to MODIFY_PIN_FINISH control command transmission (clear display or display wait message) */ + void finish(); +} 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 new file mode 100644 index 00000000..36f0097d --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java @@ -0,0 +1,48 @@ +/* +* Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + + +/** + * user interface for "software pin-entry" of + *
    + *
  • current pin and new pin (change pin) + *
  • new pin (pin activation, no current pin) + *
  • puk and new pin (probably verify only?) + *
+ * @author Clemens Orthacker + */ +public interface ModifyPINProvider { + + /** + * + * @param spec + * @param retries + * @return null if no old value for this pin + * @throws at.gv.egiz.smcc.CancelledException if cancelled by user + * @throws java.lang.InterruptedException + */ + public char[] provideCurrentPIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException; + + public char[] provideNewPIN(PINSpec spec) + 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 new file mode 100644 index 00000000..5199977b --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java @@ -0,0 +1,42 @@ +/* +* Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + + +/** + * Display messages for pinpad pin-entry. + * Provides an interface for two types of pinpad pin-entry: pinpad-direct and pinpad-start/finish + * @author clemens.orthacker@iaik.tugraz.at + */ +public interface PINGUI extends PINProvider { + + void enterPINDirect(PINSpec spec, int retries) + throws CancelledException, InterruptedException; + + /** + * @throws CancelledException, InterruptedException if signature-data dialog is interrupted or cancelled + */ + void enterPIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException; + void validKeyPressed(); + void correctionButtonPressed(); + void allKeysCleared(); + +} 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 new file mode 100644 index 00000000..3bf49888 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java @@ -0,0 +1,49 @@ +/* +* Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + + +/** + * The number of retries is not fixed and there is no way (?) to obtain this value. + * A PINProvider should therefore maintain an internal retry counter or flag + * to decide whether or not to warn the user (num retries passed in providePIN). + * + * Therefore PINProvider objects should not be reused. + * + * (ACOS: reload counter: between 0 and 15, where 15 meens deactivated) + * + * @author Clemens Orthacker + */ +public interface PINProvider { + + /** + * + * @param spec + * @param retries num of remaining retries or -1 if unknown + * (a positive value does not necessarily signify that there was + * already an unsuccessful PIN verification) + * @return pin != null + * @throws at.gv.egiz.smcc.CancelledException + * @throws java.lang.InterruptedException + */ + char[] providePIN(PINSpec 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 new file mode 100644 index 00000000..a1246dd6 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java @@ -0,0 +1,92 @@ +/* + * Copyright 2008 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.reader; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +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.ResetRetryCounterAPDUSpec; +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.VerifyAPDUSpec; +import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; +import at.gv.egiz.smcc.pin.gui.PINGUI; +import javax.smartcardio.Card; + +/** + * + * @author Clemens Orthacker + */ +public interface CardReader { + + + String[] FEATURES = new String[]{"NO_FEATURE", + "FEATURE_VERIFY_PIN_START", + "FEATURE_VERIFY_PIN_FINISH", + "FEATURE_MODIFY_PIN_START", + "FEATURE_MODIFY_PIN_FINISH", + "FEATURE_GET_KEY_PRESSED", + "FEATURE_VERIFY_PIN_DIRECT", + "FEATURE_MODIFY_PIN_DIRECT", + "FEATURE_MCT_READER_DIRECT", + "FEATURE_MCT_UNIVERSAL", + "FEATURE_IFD_PIN_PROPERTIES", + "FEATURE_ABORT", + "FEATURE_SET_SPE_MESSAGE", + "FEATURE_VERIFY_PIN_DIRECT_APP_ID", + "FEATURE_MODIFY_PIN_DIRECT_APP_ID", + "FEATURE_WRITE_DISPLAY", + "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); + //TODO continue list + + + Card connect() throws CardException; + + boolean hasFeature(Byte feature); + + ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec, + PINGUI pinGUI, PINSpec pinSpec, int retries) + throws CancelledException, InterruptedException, CardException, SignatureCardException; + + ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + throws CancelledException, InterruptedException, CardException, SignatureCardException; + + ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec) + throws CancelledException, InterruptedException, CardException, SignatureCardException; + + ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec, 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 new file mode 100644 index 00000000..45ea7a5a --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java @@ -0,0 +1,106 @@ +/* + * Copyright 2008 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.reader; + + +import javax.smartcardio.Card; +import javax.smartcardio.CardChannel; +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 at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec; +import at.gv.egiz.smcc.NewReferenceDataAPDUSpec; +import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.ResetRetryCounterAPDUSpec; +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.VerifyAPDUSpec; +import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.ISO7816Utils; + +/** + * + * @author Clemens Orthacker + */ +public class DefaultCardReader implements CardReader { + + protected final static Log log = LogFactory.getLog(DefaultCardReader.class); + + protected CardTerminal ct; + protected String name; + + public DefaultCardReader(CardTerminal ct) { + if (ct == null) { + throw new NullPointerException("no card or card terminal provided"); + } + this.ct = ct; + this.name = ct.getName(); + } + + @Override + public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec, + PINGUI pinGUI, PINSpec pinSpec, int retries) + throws SignatureCardException, CardException, InterruptedException { + + log.debug("VERIFY"); + return channel.transmit(ISO7816Utils.createVerifyAPDU(apduSpec, pinGUI.providePIN(pinSpec, retries))); + } + + @Override + public ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + throws SignatureCardException, CardException, InterruptedException { + log.debug("MODIFY (CHANGE_REFERENCE_DATA)"); + char[] oldPin = pinGUI.provideCurrentPIN(pinSpec, retries); + char[] newPin = pinGUI.provideNewPIN(pinSpec); + return channel.transmit(ISO7816Utils.createChangeReferenceDataAPDU(apduSpec, oldPin, newPin)); + } + + @Override + public ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec) + throws SignatureCardException, CardException, InterruptedException { + log.debug("MODIFY (NEW_REFERENCE_DATA)"); + char[] newPIN = pinGUI.provideNewPIN(pinSpec); + return channel.transmit(ISO7816Utils.createNewReferenceDataAPDU(apduSpec, newPIN)); + } + + @Override + public ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + throws InterruptedException, CardException, SignatureCardException { + log.debug("MODIFY (RESET_RETRY_COUNTER)"); + //TODO + return modify(channel, (ChangeReferenceDataAPDUSpec) apduSpec, pinGUI, pinSpec, retries); + } + + @Override + public Card connect() throws CardException { + log.debug("connect icc"); + return ct.connect("*"); + } + + @Override + public boolean hasFeature(Byte feature) { + return false; + } + +} 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 new file mode 100644 index 00000000..c2537af8 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java @@ -0,0 +1,703 @@ +/* + * Copyright 2008 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.reader; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Map; + +import javax.smartcardio.Card; +import javax.smartcardio.CardChannel; +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 at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec; +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.ResetRetryCounterAPDUSpec; +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.TimeoutException; +import at.gv.egiz.smcc.VerifyAPDUSpec; +import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.SMCCHelper; + +/** + * + * @author Clemens Orthacker + */ +public class PinpadCardReader extends DefaultCardReader { + + public static final int PIN_ENTRY_POLLING_INTERVAL = 10; + + protected final static Log log = LogFactory.getLog(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 + + /** + * supported features and respective control codes + */ + protected Map features; + protected boolean VERIFY, MODIFY, VERIFY_DIRECT, MODIFY_DIRECT; + + public PinpadCardReader(CardTerminal ct, Map features) { + super(ct); + if (features == null) { + throw new NullPointerException("Pinpad card reader does not support any features"); + } + this.features = features; + + if (features.containsKey(FEATURE_VERIFY_PIN_START) && + features.containsKey(FEATURE_GET_KEY_PRESSED) && + features.containsKey(FEATURE_VERIFY_PIN_FINISH)) { + VERIFY = true; + } + if (features.containsKey(FEATURE_MODIFY_PIN_START) && + features.containsKey(FEATURE_GET_KEY_PRESSED) && + features.containsKey(FEATURE_MODIFY_PIN_FINISH)) { + MODIFY = true; + } + if (features.containsKey(FEATURE_VERIFY_PIN_DIRECT)) { + VERIFY_DIRECT = true; + } + if (features.containsKey(FEATURE_MODIFY_PIN_DIRECT)) { + MODIFY_DIRECT = true; + } + + if (name != null) { + name = name.toLowerCase(); + //ReinerSCT: http://support.reiner-sct.de/downloads/LINUX + // http://www.linux-club.de/viewtopic.php?f=61&t=101287&start=0 + //old: REINER SCT CyberJack 00 00 + //new (CCID): 0C4B/0300 Reiner-SCT cyberJack pinpad(a) 00 00 + //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; + } else if (name.startsWith("omnikey cardman 3621")) { + log.debug("setting custom wPINMaxExtraDigitH (0x01) for " + name); + wPINMaxExtraDigitH = 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); + bTimeOut = 0x3c; + log.debug("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; + } + } + + } + + @Override + public boolean hasFeature(Byte feature) { + return features.containsKey(feature); + } + + 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)); + } + 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"); + throw new CardException("ERROR_INVALID_PARAMETER"); + } else { + log.error("unexpected response to VERIFY_PIN_START: " + + SMCCHelper.toString(resp)); + throw new CardException("unexpected response to VERIFY_PIN_START: " + + SMCCHelper.toString(resp)); + } + } + } + + private byte GET_KEY_PRESSED(Card icc) throws CardException { + int ioctl = features.get(FEATURE_GET_KEY_PRESSED); + byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); + if (resp != null && resp.length == 1) { +// if (log.isTraceEnabled()) { +// log.trace("response " + SMCCHelper.toString(resp)); +// } + return resp[0]; + } + log.error("unexpected response to GET_KEY_PRESSED: " + + SMCCHelper.toString(resp)); + throw new CardException("unexpected response to GET_KEY_PRESSED: " + + SMCCHelper.toString(resp)); + } + + 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) + ")"); + } + byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); + if (resp != null && resp.length == 2) { + if (log.isTraceEnabled()) { + log.trace("response " + SMCCHelper.toString(resp)); + } + return resp; + } + log.error("unexpected response to VERIFY_PIN_FINISH: " + + SMCCHelper.toString(resp)); + throw new CardException("unexpected response to VERIFY_PIN_FINISH: " + + SMCCHelper.toString(resp)); + } + + private void MODIFY_PIN_START(Card icc, byte[] PIN_MODIFY) throws CardException { + int ioctl = features.get(FEATURE_MODIFY_PIN_START); + if (log.isTraceEnabled()) { + log.trace("MODFIY_PIN_START (" + Integer.toHexString(ioctl) + + ") " + SMCCHelper.toString(PIN_MODIFY)); + } + 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"); + throw new CardException("ERROR_INVALID_PARAMETER"); + } else { + log.error("unexpected response to MODIFY_PIN_START: " + + SMCCHelper.toString(resp)); + throw new CardException("unexpected response to MODIFY_PIN_START: " + + SMCCHelper.toString(resp)); + } + } + } + + 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) + ")"); + } + byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); + if (resp != null && resp.length == 2) { + if (log.isTraceEnabled()) { + log.trace("response " + SMCCHelper.toString(resp)); + } + return resp; + } + log.error("unexpected response to MODIFY_PIN_FINISH: " + + SMCCHelper.toString(resp)); + throw new CardException("unexpected response to MODIFY_PIN_FINISH: " + + SMCCHelper.toString(resp)); + } + + 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)); + } + byte[] resp = icc.transmitControlCommand(ioctl, PIN_VERIFY); + if (log.isTraceEnabled()) { + log.trace("response " + SMCCHelper.toString(resp)); + } + return resp; + } + + private byte[] verifyPin(Card icc, byte[] PIN_VERIFY, PINGUI pinGUI) + throws SignatureCardException, CardException, InterruptedException { + +// pinGUI.enterPIN(pinSpec, retries); + + log.debug("VERIFY_PIN_START [" + FEATURES[FEATURE_VERIFY_PIN_START] + "]"); + VERIFY_PIN_START(icc, PIN_VERIFY); + + byte resp; + do { + resp = GET_KEY_PRESSED(icc); + if (resp == (byte) 0x00) { + synchronized(this) { + try { + wait(PIN_ENTRY_POLLING_INTERVAL); + } catch (InterruptedException ex) { + log.error("interrupted in VERIFY_PIN"); + } + } + } else if (resp == (byte) 0x0d) { + log.debug("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)"); + break; // returns 0x6401 + } else if (resp == (byte) 0x08) { + log.debug("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)"); + pinGUI.correctionButtonPressed(); + } else if (resp == (byte) 0x0e) { + log.debug("GET_KEY_PRESSED: 0x0e (timeout occured)"); + break; // return 0x6400 + } else if (resp == (byte) 0x40) { + log.debug("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"); + pinGUI.allKeysCleared(); + } else { + log.error("unexpected response to GET_KEY_PRESSED: " + + Integer.toHexString(resp)); + throw new CardException("unexpected response to GET_KEY_PRESSED: " + + Integer.toHexString(resp)); + } + } while (true); + + return VERIFY_PIN_FINISH(icc); + } + + /** + * 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) + throws PINOperationAbortedException, CardException { + + byte pinConfirmations = (byte) 0x00; //b0: new pin not entered (0) / entered (1) + //b1: current pin not entered (0) / entered (1) + byte bConfirmPIN = PIN_MODIFY[9]; + +// if ((bConfirmPIN & (byte) 0x02) == 0) { +// log.debug("no current PIN entry requested"); +// pinGUI.enterNewPIN(pINSpec); +// } else { +// log.debug("current PIN entry requested"); +// pinGUI.enterCurrentPIN(pINSpec, retries); +// } + + log.debug("MODIFY_PIN_START [" + FEATURES[FEATURE_MODIFY_PIN_START] + "]"); + MODIFY_PIN_START(icc, PIN_MODIFY); + + byte resp; + while (true) { + resp = GET_KEY_PRESSED(icc); + if (resp == (byte) 0x00) { + synchronized(this) { + try { + wait(PIN_ENTRY_POLLING_INTERVAL); + } catch (InterruptedException ex) { + 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.debug("GET_KEY_PRESSED: 0x0d (user confirmed)"); + if (pinConfirmations == bConfirmPIN) { + break; + } else if ((bConfirmPIN & (byte) 0x02) == 0 || + (pinConfirmations & (byte) 0x02) == (byte) 0x02) { + // no current pin entry or current pin entry already performed + if ((pinConfirmations & (byte) 0x01) == 0) { + // new pin + pinConfirmations |= (byte) 0x01; + pinGUI.confirmNewPIN(pINSpec); + } // else: new pin confirmed + } else { + // current pin entry + pinConfirmations |= (byte) 0x02; + pinGUI.enterNewPIN(pINSpec); + } + } 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)"); + break; // returns 0x6401 + } else if (resp == (byte) 0x08) { + log.debug("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)"); + pinGUI.correctionButtonPressed(); + } else if (resp == (byte) 0x0e) { + log.debug("GET_KEY_PRESSED: 0x0e (timeout occured)"); + break; // return 0x6400 + } else if (resp == (byte) 0x40) { + log.debug("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"); + pinGUI.allKeysCleared(); + } else { + log.error("unexpected response to GET_KEY_PRESSED: " + + Integer.toHexString(resp)); + throw new CardException("unexpected response to GET_KEY_PRESSED: " + + Integer.toHexString(resp)); + } + + } + + pinGUI.finish(); + return MODIFY_PIN_FINISH(icc); + } + + 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)); + } + byte[] resp = icc.transmitControlCommand(ioctl, PIN_MODIFY); + if (log.isTraceEnabled()) { + log.trace("response " + SMCCHelper.toString(resp)); + } + return resp; + } + + protected byte[] createPINModifyStructure(NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) { + + ByteArrayOutputStream s = new ByteArrayOutputStream(); + // bTimeOut + s.write(bTimeOut); + // bTimeOut2 + s.write(bTimeOut2); + // bmFormatString + s.write(1 << 7 // system unit = byte + | (0xF & apduSpec.getPinPosition()) << 3 + | (0x1 & apduSpec.getPinJustification() << 2) + | (0x3 & apduSpec.getPinFormat())); + // bmPINBlockString + s.write((0xF & apduSpec.getPinLengthSize()) << 4 + | (0xF & apduSpec.getPinLength())); + // bmPINLengthFormat + s.write(// system unit = bit + (0xF & apduSpec.getPinLengthPos())); + // bInsertionOffsetOld + s.write(0x00); + // bInsertionOffsetNew + s.write(apduSpec.getPinInsertionOffsetNew()); + // wPINMaxExtraDigit + s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL)); + s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH)); + // 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 + s.write(0x09); + s.write(0x04); + // bMsgIndex1 + s.write(0x01); + // bMsgIndex2 + s.write(0x02); + // bMsgIndex3 + s.write(0x00); + + // bTeoPrologue + s.write(0x00); + s.write(0x00); + s.write(0x00); + // ulDataLength + s.write(apduSpec.getApdu().length); + s.write(0x00); + s.write(0x00); + s.write(0x00); + // abData + try { + s.write(apduSpec.getApdu()); + } catch (IOException e) { + // As we are dealing with ByteArrayOutputStreams no exception is to be + // expected. + throw new RuntimeException(e); + } + + return s.toByteArray(); + + } + + protected byte[] createPINModifyStructure(ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) { + //TODO bInsertionOffsetOld (0x00), bConfirmPIN (0x01), bNumberMessage (0x02), bMsgIndex1/2/3 + + ByteArrayOutputStream s = new ByteArrayOutputStream(); + // bTimeOut + s.write(bTimeOut); + // bTimeOut2 + s.write(bTimeOut2); + // bmFormatString + s.write(1 << 7 // system unit = byte + | (0xF & apduSpec.getPinPosition()) << 3 + | (0x1 & apduSpec.getPinJustification() << 2) + | (0x3 & apduSpec.getPinFormat())); + // bmPINBlockString + s.write((0xF & apduSpec.getPinLengthSize()) << 4 + | (0xF & apduSpec.getPinLength())); + // bmPINLengthFormat + s.write(// system unit = bit + (0xF & apduSpec.getPinLengthPos())); + // bInsertionOffsetOld (0x00 for no old pin?) + s.write(apduSpec.getPinInsertionOffsetOld()); + // bInsertionOffsetNew + s.write(apduSpec.getPinInsertionOffsetNew()); + // wPINMaxExtraDigit + s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL)); + s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH)); + // bConfirmPIN + s.write(0x03); + // bEntryValidationCondition + s.write(bEntryValidationCondition); + // bNumberMessage + s.write(0x03); + // wLangId English (United States), see http://www.usb.org/developers/docs/USB_LANGIDs.pdf + s.write(0x09); + s.write(0x04); + // bMsgIndex1 + s.write(0x00); + // bMsgIndex2 + s.write(0x01); + // bMsgIndex3 + s.write(0x02); + + // bTeoPrologue + s.write(0x00); + s.write(0x00); + s.write(0x00); + // ulDataLength + s.write(apduSpec.getApdu().length); + s.write(0x00); + s.write(0x00); + s.write(0x00); + // abData + try { + s.write(apduSpec.getApdu()); + } catch (IOException e) { + // As we are dealing with ByteArrayOutputStreams no exception is to be + // expected. + throw new RuntimeException(e); + } + + return s.toByteArray(); + + } + + protected byte[] createPINVerifyStructure(VerifyAPDUSpec apduSpec, PINSpec pinSpec) { + + ByteArrayOutputStream s = new ByteArrayOutputStream(); + // bTimeOut + s.write(bTimeOut); + // bTimeOut2 + s.write(bTimeOut2); + // bmFormatString + s.write(1 << 7 // system unit = byte + | (0xF & apduSpec.getPinPosition()) << 3 + | (0x1 & apduSpec.getPinJustification() << 2) + | (0x3 & apduSpec.getPinFormat())); + // bmPINBlockString + s.write((0xF & apduSpec.getPinLengthSize()) << 4 + | (0xF & apduSpec.getPinLength())); + // 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 + // bEntryValidationCondition + s.write(bEntryValidationCondition); + // bNumberMessage + s.write(0x01); + // wLangId + s.write(0x09); + s.write(0x04); + // bMsgIndex + s.write(0x00); + // bTeoPrologue + s.write(0x00); + s.write(0x00); + s.write(0x00); + // ulDataLength + s.write(apduSpec.getApdu().length); + s.write(0x00); + s.write(0x00); + s.write(0x00); + // abData + try { + s.write(apduSpec.getApdu()); + } catch (IOException e) { + // As we are dealing with ByteArrayOutputStreams no exception is to be + // expected. + throw new RuntimeException(e); + } + + return s.toByteArray(); + + } + + @Override + public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec, + PINGUI pinGUI, PINSpec pinSpec, int retries) + throws SignatureCardException, CardException, InterruptedException { + + ResponseAPDU resp = null; + + byte[] s = createPINVerifyStructure(apduSpec, pinSpec); + Card icc = channel.getCard(); + + if (VERIFY) { + pinGUI.enterPIN(pinSpec, retries); + 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] + "]"); + resp = new ResponseAPDU(VERIFY_PIN_DIRECT(icc, s)); + } else { + log.warn("falling back to default pin-entry"); + return super.verify(channel, apduSpec, pinGUI, pinSpec, retries); + } + + switch (resp.getSW()) { + case 0x6400: + log.debug("SPE operation timed out."); + throw new TimeoutException(); + case 0x6401: + 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(); + case 0x6480: + log.debug("SPE operation was aborted by the 'Cancel' operation " + + "at the host system."); + case 0x6b80: + log.info("Invalid parameter in passed structure."); + default: + return resp; + } + } + + @Override + public ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec, int retries) + throws SignatureCardException, CardException, InterruptedException { + + ResponseAPDU resp = null; + + byte[] s = createPINModifyStructure(apduSpec, pinSpec); + Card icc = channel.getCard(); + + if (MODIFY) { + pinGUI.enterCurrentPIN(pinSpec, retries); + 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] + "]"); + resp = new ResponseAPDU(MODIFY_PIN_DIRECT(icc, s)); + } else { + log.warn("falling back to default pin-entry"); + return super.modify(channel, apduSpec, pinGUI, pinSpec, retries); + } + + switch (resp.getSW()) { + case 0x6400: + log.debug("SPE operation timed out."); + throw new TimeoutException(); + case 0x6401: + log.debug("SPE operation was cancelled by the 'Cancel' button."); + throw new CancelledException(); + case 0x6402: + log.debug("Modify PIN operation failed because two 'new PIN' " + + "entries do not match"); + throw new PINConfirmationException(); + case 0x6403: + 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."); + case 0x6b80: + log.info("Invalid parameter in passed structure."); + default: + return resp; + } + } + + @Override + public ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec pinSpec) + throws SignatureCardException, CardException, InterruptedException { + + ResponseAPDU resp = null; + + byte[] s = createPINModifyStructure(apduSpec, pinSpec); + Card icc = channel.getCard(); + + if (MODIFY) { + pinGUI.enterNewPIN(pinSpec); + 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] + "]"); + resp = new ResponseAPDU(MODIFY_PIN_DIRECT(icc, s)); + } else { + log.warn("falling back to default pin-entry"); + return super.modify(channel, apduSpec, pinGUI, pinSpec); + } + + switch (resp.getSW()) { + case 0x6400: + log.debug("SPE operation timed out."); + throw new TimeoutException(); + case 0x6401: + log.debug("SPE operation was cancelled by the 'Cancel' button."); + throw new CancelledException(); + case 0x6402: + log.debug("Modify PIN operation failed because two 'new PIN' " + + "entries do not match"); + throw new PINConfirmationException(); + case 0x6403: + 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."); + case 0x6b80: + log.info("Invalid parameter in passed structure."); + default: + return resp; + } + } + + @Override + public ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec, + ModifyPINGUI pinGUI, PINSpec 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 new file mode 100644 index 00000000..eb197d9f --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java @@ -0,0 +1,128 @@ +/* + * Copyright 2008 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.reader; + +import at.gv.egiz.smcc.conf.SMCCConfiguration; +import at.gv.egiz.smcc.util.SMCCHelper; +import java.util.HashMap; +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; + +/** + * + * @author Clemens Orthacker + */ +public class ReaderFactory { + + protected final static Log log = LogFactory.getLog(ReaderFactory.class); + + protected SMCCConfiguration configuration; + + private ReaderFactory() { + } + + /** + * @param configuration the configuration to set + */ + public void setConfiguration(SMCCConfiguration configuration) { + this.configuration = configuration; + } + + public static CardReader getReader(Card icc, CardTerminal ct) { + + String name = ct.getName(); + log.info("creating reader " + name); + + Map features = queryFeatures(icc); + boolean disablePinpad = false; + CardReader reader; + + //TODO query application context for reader config +// if (configuration != null) { +// String disablePinpad = configuration.getProperty(SMCCConfiguration.DISABLE_PINPAD_P); +// log.debug("setting disablePinpad to " + Boolean.parseBoolean(disablePinpad)); +// reader.setDisablePinpad(Boolean.parseBoolean(disablePinpad)); +// } + log.warn("card reader configuration is not considered"); + + if (features.isEmpty() || disablePinpad) { + reader = new DefaultCardReader(ct); + } else { + reader = new PinpadCardReader(ct, features); + } + + return reader; + } + + private static int 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); + + private static Map queryFeatures(Card icc) { + Map features = new HashMap(); + + if (icc == null) { + 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)); + } + byte[] resp = icc.transmitControlCommand(IOCTL_GET_FEATURE_REQUEST, + new byte[0]); + + if (log.isTraceEnabled()) { + log.trace("Response TLV " + SMCCHelper.toString(resp)); + } + // tag + // length in bytes (always 4) + // control code value for supported feature (in big endian) + for (int i = 0; i < resp.length; i += 6) { + Byte feature = new Byte(resp[i]); + Integer ioctl = new Integer((0xff & resp[i + 2]) << 24) | + ((0xff & resp[i + 3]) << 16) | + ((0xff & resp[i + 4]) << 8) | + (0xff & resp[i + 5]); + if (log.isInfoEnabled()) { + 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"); + } + } + return features; + } + +} diff --git a/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java index 137de509..affb06ff 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java @@ -51,6 +51,7 @@ public abstract class AbstractAppl implements CardAppl { return files; } + @Override public abstract void setPin(int kid, char[] value); } \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java index 6017bcce..3dfc8510 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java @@ -28,15 +28,15 @@ import javax.smartcardio.CardException; @SuppressWarnings("restriction") public abstract class CardEmul extends Card { - protected Thread exclThread = null; - protected CardChannel channel = newCardChannel(this); + protected Thread exclThread; // = null; + protected CardChannel channel; // = newCardChannel(this); protected List applications = new ArrayList(); public CardEmul() { super(); } - protected abstract CardChannelEmul newCardChannel(CardEmul cardEmul); +// protected abstract CardChannelEmul newCardChannel(CardEmul cardEmul); @Override public void beginExclusive() throws CardException { @@ -71,9 +71,9 @@ public abstract class CardEmul extends Card { @Override public void disconnect(boolean reset) throws CardException { - if (reset) { - channel = newCardChannel(this); - } +// if (reset) { +// channel = newCardChannel(this); +// } } @Override @@ -93,7 +93,7 @@ public abstract class CardEmul extends Card { } public AbstractAppl getApplication(byte[] fid) { - + for(AbstractAppl appl : applications) { if (Arrays.equals(appl.getAID(), fid) || Arrays.equals(appl.getFID(), fid)) { return appl; diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java index b3bd07ab..44e48836 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java @@ -16,12 +16,14 @@ */ package at.gv.egiz.smcc; +import at.gv.egiz.smcc.pin.gui.CancelPINProvider; +import at.gv.egiz.smcc.pin.gui.InterruptPINProvider; +import at.gv.egiz.smcc.pin.gui.CancelChangePINProvider; import static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.List; @@ -32,119 +34,15 @@ import org.junit.Test; import at.gv.egiz.smcc.SignatureCard.KeyboxName; import at.gv.egiz.smcc.acos.A04ApplDEC; +import at.gv.egiz.smcc.pin.gui.DummyPINGUI; +import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider; +import org.junit.Ignore; @SuppressWarnings("restriction") public abstract class CardTest { - public class TestPINProvider implements PINProvider { - - int provided = 0; - - char[] pin; - - public TestPINProvider(char[] pin) { - super(); - this.pin = pin; - } - - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - provided++; - return pin; - } - - public int getProvided() { - return provided; - } - - } - - public class TestChangePINProvider extends TestPINProvider implements - ChangePINProvider { - - char[] oldPin; - - public TestChangePINProvider(char[] oldPin, char[] pin) { - super(pin); - this.oldPin = oldPin; - } - - @Override - public char[] provideOldPIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - return oldPin; - } - - } - - public class TestInvalidPINProvider implements PINProvider { - - int provided = 0; - int numWrongTries = 0; - - char[] pin; - - public TestInvalidPINProvider(char[] pin, int numWrongTries) { - super(); - this.pin = pin; - this.numWrongTries = numWrongTries; - } - - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - if (provided >= numWrongTries) { - throw new CancelledException("Number of wrong tries reached: " + provided); - } else { - provided++; - return pin; - } - } - - public int getProvided() { - return provided; - } - } - - public class TestInvalidChangePINProvider implements ChangePINProvider { - - int provided = 0; - int numWrongTries = 0; - - char[] pin; - char[] oldPin; - - /** emulate ChangePinProvider */ - public TestInvalidChangePINProvider(char[] oldPin, char[] newPin, int numWrongTries) { - super(); - this.pin = newPin; - this.oldPin = oldPin; - this.numWrongTries = numWrongTries; - } - - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - return pin; - } - - public int getProvided() { - return provided; - } - - @Override - public char[] provideOldPIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - if (provided >= numWrongTries) { - throw new CancelledException("Number of wrong tries reached: " + provided); - } else { - provided++; - return oldPin; - } - } - } - public CardTest() { super(); } @@ -167,7 +65,7 @@ public abstract class CardTest { SignatureCard signatureCard = createSignatureCard(); - TestPINProvider pinProvider = new TestPINProvider(pin); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider(pin); byte[] idlink = signatureCard.getInfobox("IdentityLink", pinProvider, null); @@ -184,13 +82,7 @@ public abstract class CardTest { SignatureCard signatureCard = createSignatureCard(); - PINProvider pinProvider = new PINProvider() { - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - throw new CancelledException(); - } - }; + PINGUI pinProvider = new CancelPINProvider(); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR, pinProvider, @@ -205,13 +97,7 @@ public abstract class CardTest { SignatureCard signatureCard = createSignatureCard(); - PINProvider pinProvider = new PINProvider() { - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - throw new CancelledException(); - } - }; + PINGUI pinProvider = new CancelPINProvider(); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR, @@ -226,13 +112,7 @@ public abstract class CardTest { SignatureCard signatureCard = createSignatureCard(); - PINProvider pinProvider = new PINProvider() { - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - throw new InterruptedException(); - } - }; + PINGUI pinProvider = new InterruptPINProvider(); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR, @@ -247,13 +127,7 @@ public abstract class CardTest { SignatureCard signatureCard = createSignatureCard(); - PINProvider pinProvider = new PINProvider() { - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - throw new InterruptedException(); - } - }; + PINGUI pinProvider = new InterruptPINProvider(); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR, @@ -268,11 +142,11 @@ public abstract class CardTest { final SignatureCard signatureCard = createSignatureCard(); - PINProvider pinProvider = new PINProvider() { + PINGUI pinProvider = new DummyPINGUI() { @Override public char[] providePIN(PINSpec spec, int retries) throws CancelledException, InterruptedException { - + try { signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR); assertTrue(false); @@ -281,10 +155,10 @@ public abstract class CardTest { // expected throw new CancelledException(); } - + } }; - + signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR, pinProvider, null); @@ -298,7 +172,7 @@ public abstract class CardTest { final SignatureCard signatureCard = createSignatureCard(); - PINProvider pinProvider = new PINProvider() { + PINGUI pinProvider = new DummyPINGUI() { @Override public char[] providePIN(PINSpec spec, int retries) throws CancelledException, InterruptedException { @@ -311,7 +185,6 @@ public abstract class CardTest { // expected throw new CancelledException(); } - } }; @@ -339,13 +212,7 @@ public abstract class CardTest { PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(); - PINProvider pinProvider = new PINProvider() { - @Override - public char[] providePIN(PINSpec spec, int retries) - throws CancelledException, InterruptedException { - throw new CancelledException(); - } - }; + ModifyPINGUI pinProvider = new CancelChangePINProvider(); List specs = signatureCard.getPINSpecs(); diff --git a/smcc/src/test/java/at/gv/egiz/smcc/PIN.java b/smcc/src/test/java/at/gv/egiz/smcc/PIN.java index ae883727..2cda0c2f 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/PIN.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/PIN.java @@ -23,19 +23,23 @@ public class PIN { public static final int STATE_PIN_VERIFIED = 1; public static final int STATE_PIN_BLOCKED = -1; + + public static final int STATE_PIN_NOTACTIVE = 2; public byte[] pin; public int kid; - public int state = STATE_RESET; + public int state; // = STATE_RESET; - public int kfpc = 10; + public int kfpc; // = 10; - public PIN(byte[] pin, int kid, int kfpc) { + //TODO also provde default constructor without state param + public PIN(byte[] pin, int kid, int kfpc, int state) { this.pin = pin; this.kid = kid; this.kfpc = kfpc; + this.state = state; } } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java index 9fd96d73..f4ac5c35 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java @@ -40,7 +40,7 @@ public class A03ApplDEC extends ACOSApplDEC { putFile(new File(FID_EF_INFOBOX, EF_INFOBOX, FCI_EF_INFOBOX, KID_PIN_INF)); try { - pins.put(KID_PIN_INF, new PIN("0000\0\0\0\0".getBytes("ASCII"), KID_PIN_INF, 10)); + pins.put(KID_PIN_INF, new PIN("0000\0\0\0\0".getBytes("ASCII"), KID_PIN_INF, 10, PIN.STATE_RESET)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java index 58216b6b..7394bae7 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java @@ -24,13 +24,8 @@ import at.gv.egiz.smcc.CardEmul; public class A03CardEmul extends ACOSCardEmul { public A03CardEmul(A03ApplSIG applSIG, A03ApplDEC applDEC) { + channel = new A03CardChannelEmul(this); applications.add(applSIG); applications.add(applDEC); } - - @Override - protected CardChannelEmul newCardChannel(CardEmul cardEmul) { - return new A03CardChannelEmul(this); - } - } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java index 776c0370..3a8ac41c 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java @@ -22,15 +22,16 @@ import java.util.Arrays; import org.junit.Test; -import at.gv.egiz.smcc.ACOSCard; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.CardEmul; import at.gv.egiz.smcc.CardNotSupportedException; import at.gv.egiz.smcc.CardTerminalEmul; +import at.gv.egiz.smcc.pin.gui.ChangePINProvider; import at.gv.egiz.smcc.LockedException; import at.gv.egiz.smcc.NotActivatedException; import at.gv.egiz.smcc.PINFormatException; import at.gv.egiz.smcc.PINMgmtSignatureCard; +import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider; import at.gv.egiz.smcc.PINSpec; import at.gv.egiz.smcc.SignatureCard; import at.gv.egiz.smcc.SignatureCardException; @@ -74,12 +75,12 @@ public class A03CardTest extends ACOSCardTest { char[] pin = defaultPin; for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) { - signatureCard.verifyPIN(pinSpec, new TestPINProvider(pin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin)); char[] newPin = new char[i]; Arrays.fill(newPin, '0'); signatureCard - .changePIN(pinSpec, new TestChangePINProvider(pin, newPin)); - signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin)); + .changePIN(pinSpec, new ChangePINProvider(pin, newPin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin)); pin = newPin; } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java index 70925aa6..dd44d05b 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java @@ -24,14 +24,9 @@ import at.gv.egiz.smcc.CardEmul; public class A04CardEmul extends ACOSCardEmul { public A04CardEmul(A04ApplSIG applSIG, A04ApplDEC applDEC) { + channel = new A04CardChannelEmul(this); applications.add(applSIG); applications.add(applDEC); } - - @Override - protected CardChannelEmul newCardChannel(CardEmul cardEmul) { - return new A04CardChannelEmul(this); - } - } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java index d15e80d7..1cbea1b3 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java @@ -28,7 +28,6 @@ import java.util.Arrays; import org.junit.BeforeClass; import org.junit.Test; -import at.gv.egiz.smcc.ACOSCard; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.CardEmul; import at.gv.egiz.smcc.CardNotSupportedException; @@ -41,7 +40,8 @@ import at.gv.egiz.smcc.PINSpec; import at.gv.egiz.smcc.SignatureCard; import at.gv.egiz.smcc.SignatureCardException; import at.gv.egiz.smcc.SignatureCardFactory; -import at.gv.egiz.smcc.CardTest.TestPINProvider; +import at.gv.egiz.smcc.pin.gui.ChangePINProvider; +import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider; public class A04CardTest extends ACOSCardTest { @@ -88,8 +88,8 @@ public class A04CardTest extends ACOSCardTest { char[] newPin = new char[i]; Arrays.fill(newPin, '0'); signatureCard - .changePIN(pinSpec, new TestChangePINProvider(pin, newPin)); - signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin)); + .changePIN(pinSpec, new ChangePINProvider(pin, newPin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin)); pin = newPin; } @@ -111,7 +111,7 @@ public class A04CardTest extends ACOSCardTest { SignatureCard signatureCard = factory.createSignatureCard(card, new CardTerminalEmul(card)); - TestPINProvider pinProvider = new TestPINProvider(pin); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider(pin); byte[] idlink = signatureCard.getInfobox("IdentityLink", pinProvider, null); @@ -129,7 +129,7 @@ public class A04CardTest extends ACOSCardTest { SignatureCard signatureCard = createSignatureCard(); - TestPINProvider pinProvider = new TestPINProvider(pin); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider(pin); byte[] idlink = signatureCard.getInfobox("IdentityLink", pinProvider, null); diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java index 08979536..09a754f3 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java @@ -297,7 +297,7 @@ public abstract class ACOSApplDEC extends ACOSAppl { System.arraycopy(C_CH_EKEY, 0, EF_C_CH_EKEY, 0, C_CH_EKEY.length); putFile(new File(FID_EF_C_CH_EKEY, EF_C_CH_EKEY, FCI_EF_C_CH_EKEY)); try { - pins.put(KID_PIN_DEC, new PIN("1234\0\0\0\0".getBytes("ASCII"), KID_PIN_DEC, 10)); + pins.put(KID_PIN_DEC, new PIN("1234\0\0\0\0".getBytes("ASCII"), KID_PIN_DEC, 10, PIN.STATE_RESET)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java index e476b434..6ab5903a 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java @@ -221,7 +221,7 @@ public abstract class ACOSApplSIG extends ACOSAppl { // PINs try { - pins.put(KID_PIN_SIG, new PIN(Arrays.copyOf("123456".getBytes("ASCII"), 8), KID_PIN_SIG, 3)); + pins.put(KID_PIN_SIG, new PIN(Arrays.copyOf("123456".getBytes("ASCII"), 8), KID_PIN_SIG, 3, PIN.STATE_RESET)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java index 56d1e4b2..4f012739 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java @@ -16,26 +16,23 @@ */ package at.gv.egiz.smcc.acos; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import org.junit.Test; -import at.gv.egiz.smcc.ACOSCard; import at.gv.egiz.smcc.CardEmul; import at.gv.egiz.smcc.CardNotSupportedException; import at.gv.egiz.smcc.CardTest; import at.gv.egiz.smcc.LockedException; import at.gv.egiz.smcc.NotActivatedException; +import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider; import at.gv.egiz.smcc.SignatureCard; import at.gv.egiz.smcc.SignatureCardException; import at.gv.egiz.smcc.SignatureCard.KeyboxName; @@ -60,7 +57,7 @@ public abstract class ACOSCardTest extends CardTest { appl.clearInfobox(); byte[] idlink = signatureCard.getInfobox("IdentityLink", - new TestPINProvider(pin), null); + new SMCCTestPINProvider(pin), null); assertNull(idlink); } @@ -76,7 +73,7 @@ public abstract class ACOSCardTest extends CardTest { ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC); appl.setInfoboxHeader((byte) 0xFF); - signatureCard.getInfobox("IdentityLink", new TestPINProvider(pin), null); + signatureCard.getInfobox("IdentityLink", new SMCCTestPINProvider(pin), null); } @@ -138,7 +135,7 @@ public abstract class ACOSCardTest extends CardTest { byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), - KeyboxName.SECURE_SIGNATURE_KEYPAIR, new TestPINProvider(pin), null); + KeyboxName.SECURE_SIGNATURE_KEYPAIR, new SMCCTestPINProvider(pin), null); assertNotNull(signature); @@ -158,7 +155,7 @@ public abstract class ACOSCardTest extends CardTest { byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), - KeyboxName.CERITIFIED_KEYPAIR, new TestPINProvider(pin), null); + KeyboxName.CERITIFIED_KEYPAIR, new SMCCTestPINProvider(pin), null); assertNotNull(signature); @@ -171,7 +168,7 @@ public abstract class ACOSCardTest extends CardTest { SignatureCard signatureCard = createSignatureCard(); - TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray()); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray()); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR, @@ -186,7 +183,7 @@ public abstract class ACOSCardTest extends CardTest { SignatureCard signatureCard = createSignatureCard(); - TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray()); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("0000".toCharArray()); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR, @@ -204,7 +201,7 @@ public abstract class ACOSCardTest extends CardTest { ACOSApplSIG appl = (ACOSApplSIG) card.getApplication(ACOSAppl.AID_SIG); appl.setPin(ACOSApplSIG.KID_PIN_SIG, null); - TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray()); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray()); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR, @@ -222,7 +219,7 @@ public abstract class ACOSCardTest extends CardTest { ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC); appl.setPin(ACOSApplDEC.KID_PIN_DEC, null); - TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray()); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("0000".toCharArray()); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR, diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java new file mode 100644 index 00000000..dffe7e29 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public class CancelChangePINProvider extends DummyChangePINGUI implements ModifyPINGUI { + + public CancelChangePINProvider() { + } + + @Override + public char[] provideCurrentPIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException { + throw new CancelledException("cancelled by cancelPINProvider"); + } + + @Override + public char[] provideNewPIN(PINSpec spec) + throws CancelledException, InterruptedException { + throw new CancelledException("cancelled by cancelPINProvider"); + } + +} \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java new file mode 100644 index 00000000..77f19345 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java @@ -0,0 +1,29 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public class CancelPINProvider extends DummyPINGUI implements PINGUI { + + @Override + public char[] providePIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException { + throw new CancelledException("cancelled by cancelPINProvider"); + } +} \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java new file mode 100644 index 00000000..5eb8b9a1 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java @@ -0,0 +1,49 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public class ChangePINProvider extends DummyChangePINGUI implements ModifyPINGUI { + + int provided = 0; + char[] pin; + char[] oldPin; + + public ChangePINProvider(char[] oldPin, char[] pin) { + this.pin = pin; + this.oldPin = oldPin; + } + + public int getProvided() { + return provided; + } + + @Override + public char[] provideCurrentPIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException { + provided++; + return oldPin; + } + + @Override + public char[] provideNewPIN(PINSpec spec) { + return pin; + } + +} diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java new file mode 100644 index 00000000..fff89409 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java @@ -0,0 +1,68 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public abstract class DummyChangePINGUI implements ModifyPINGUI { + + @Override + public void validKeyPressed() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void correctionButtonPressed() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void allKeysCleared() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void finish() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void finishDirect() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void modifyPINDirect(PINSpec spec, int retries) throws CancelledException, InterruptedException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void enterCurrentPIN(PINSpec spec, int retries) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void enterNewPIN(PINSpec spec) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void confirmNewPIN(PINSpec spec) { + throw new UnsupportedOperationException("Not supported yet."); + } +} \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java new file mode 100644 index 00000000..4d99b5c1 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java @@ -0,0 +1,48 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public abstract class DummyPINGUI implements PINGUI { + + @Override + public void enterPINDirect(PINSpec spec, int retries) throws CancelledException, InterruptedException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void enterPIN(PINSpec spec, int retries) throws CancelledException, InterruptedException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void validKeyPressed() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void correctionButtonPressed() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void allKeysCleared() { + throw new UnsupportedOperationException("Not supported yet."); + } +} \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java new file mode 100644 index 00000000..5706b888 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +@SuppressWarnings("restriction") +public class InterruptPINProvider extends DummyPINGUI implements PINGUI { + + public InterruptPINProvider() { + } + + @Override + public char[] providePIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException { + throw new InterruptedException("interrupted by cancelPINProvider"); + } + +} \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java new file mode 100644 index 00000000..69c9f42a --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public class InvalidChangePINProvider extends DummyChangePINGUI implements ModifyPINGUI { + + int provided = 0; + int numWrongTries = 0; + char[] pin; + char[] oldPin; + + /** emulate ChangePinProvider */ + public InvalidChangePINProvider(char[] oldPin, char[] newPin, int numWrongTries) { + super(); + this.pin = newPin; + this.oldPin = oldPin; + this.numWrongTries = numWrongTries; + } + + @Override + public char[] provideCurrentPIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException { + if (provided >= numWrongTries) { + throw new CancelledException("Number of wrong tries reached: " + provided); + } else { + provided++; + return oldPin; + } + } + + public int getProvided() { + return provided; + } + + @Override + public char[] provideNewPIN(PINSpec spec) { + return pin; + } +} diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java new file mode 100644 index 00000000..db01fd0d --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public class InvalidPINProvider extends DummyPINGUI implements PINGUI { + + int provided = 0; + int numWrongTries = 0; + char[] pin; + + public InvalidPINProvider(char[] pin, int numWrongTries) { + super(); + this.pin = pin; + this.numWrongTries = numWrongTries; + } + + @Override + public char[] providePIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException { + if (provided >= numWrongTries) { + throw new CancelledException("Number of wrong tries reached: " + provided); + } else { + provided++; + return pin; + } + } + + public int getProvided() { + return provided; + } +} diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java new file mode 100644 index 00000000..dffc90d7 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright 2008 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.pin.gui; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PINSpec; + +public class SMCCTestPINProvider extends DummyPINGUI implements PINGUI { + + public int provided = 0; + char[] pin; + + public SMCCTestPINProvider(char[] pin) { + this.pin = pin; + } + + @Override + public char[] providePIN(PINSpec spec, int retries) + throws CancelledException, InterruptedException { + provided++; + return pin; + } + + public int getProvided() { + return provided; + } + + +} \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java index 2ca63eea..62528e6e 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java @@ -69,27 +69,4 @@ public abstract class STARCOSAppl extends AbstractAppl implements CardAppl { pin.next().state = PIN.STATE_RESET; } } - - public void setPin(int kid, char[] value) { - PIN pin = pins.get(kid); - if (pin != null) { - if (value == null) { - pin.pin = null; - } else { - byte[] b = new byte[8]; - b[0] = (byte) (0x20 | value.length); - for(int i = 1, j = 0; i < b.length; i++) { - int h = ((j < value.length) - ? Character.digit(value[j++], 10) - : 0x0F); - int l = ((j < value.length) - ? Character.digit(value[j++], 10) - : 0x0F); - b[i] = (byte) ((h << 4) | l); - } - pin.pin = b; - } - } - } - } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java index cec305da..8741dd2d 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java @@ -16,7 +16,6 @@ */ package at.gv.egiz.smcc.starcos; -import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Random; @@ -200,12 +199,18 @@ public class STARCOSApplGewoehnlicheSignatur extends STARCOSAppl { protected byte[] EF_C_X509_CH_AUT = new byte[2000]; - - public STARCOSApplGewoehnlicheSignatur(STARCOSCardChannelEmul channel) { + + protected byte[] dst; + + public static final byte[] DST = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x89, (byte) 0x03, (byte) 0x13, (byte) 0x35, (byte) 0x10}; + public static final byte[] DST_G3 = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x80, (byte) 0x01, (byte) 0x04 }; + + public STARCOSApplGewoehnlicheSignatur(STARCOSCardChannelEmul channel, byte[] dst) { super(channel); // Files System.arraycopy(C_X509_CH_AUT, 0, EF_C_X509_CH_AUT, 0, C_X509_CH_AUT.length); putFile(new File(FID_EF_C_X509_CH_AUT, EF_C_X509_CH_AUT, FCI_EF_C_X509_CH_AUT)); + this.dst = dst; } @Override @@ -240,12 +245,19 @@ public class STARCOSApplGewoehnlicheSignatur extends STARCOSAppl { case 0x81: // EXTERNAL AUTHENTICATE } + case 0xAA: + switch (command.getP1()) { + case 0x41: + if (Arrays.equals(new byte[] {(byte) 0x80, (byte) 0x01, (byte) 0x10}, command.getData())) { + return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00}); + } + default: + return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80}); + } case 0xB6: switch (command.getP1()) { case 0x41: { // PSO - COMPUTE DIGITAL SIGNATURE - byte[] dst = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80, - (byte) 0x02, (byte) 0x00, (byte) 0x89, (byte) 0x03, (byte) 0x13, (byte) 0x35, (byte) 0x10}; if (Arrays.equals(dst, command.getData())) { securityEnv = command.getData(); return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00}); @@ -328,5 +340,10 @@ public class STARCOSApplGewoehnlicheSignatur extends STARCOSAppl { } + @Override + public void setPin(int kid, char[] value) { + throw new UnsupportedOperationException("Not supported yet."); + } + } \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java index b7835a43..c470351a 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java @@ -156,5 +156,10 @@ public class STARCOSApplInfobox extends STARCOSAppl { throw new CardException("Not supported."); } + @Override + public void setPin(int kid, char[] value) { + throw new UnsupportedOperationException("Not supported yet."); + } + } \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java index 9fb5ad37..4036ca41 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java @@ -213,16 +213,14 @@ public class STARCOSApplSichereSignatur extends STARCOSAppl { protected byte[] EF_C_X509_CH_DS = new byte[2000]; - public STARCOSApplSichereSignatur(STARCOSCardChannelEmul channel) { + public STARCOSApplSichereSignatur(STARCOSCardChannelEmul channel, byte[] SS_pin, int pinState) { super(channel); // Files System.arraycopy(C_X509_CH_DS, 0, EF_C_X509_CH_DS, 0, C_X509_CH_DS.length); putFile(new File(FID_EF_C_X509_CH_DS, EF_C_X509_CH_DS, FCI_EF_C_X509_CH_DS)); // PINs - pins.put(KID_PIN_SS, new PIN(new byte[] { (byte) 0x24, (byte) 0x12, - (byte) 0x34, (byte) 0x56, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF }, KID_PIN_SS, 3)); + pins.put(KID_PIN_SS, new PIN(SS_pin, KID_PIN_SS, 3, pinState)); } @Override @@ -344,4 +342,34 @@ public class STARCOSApplSichereSignatur extends STARCOSAppl { } + /** + * set and activate pin + * @param value if null, pin will be set to NOTACTIVE + */ + @Override + public void setPin(int kid, char[] value) { + PIN pin = pins.get(kid); + if (pin != null) { + if (value == null) { +// pin.pin = null; + //TransportPIN +// pin.pin = new byte[] { (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + pin.state = PIN.STATE_PIN_NOTACTIVE; + } else { + byte[] b = new byte[8]; + b[0] = (byte) (0x20 | value.length); + for(int i = 1, j = 0; i < b.length; i++) { + int h = ((j < value.length) + ? Character.digit(value[j++], 10) + : 0x0F); + int l = ((j < value.length) + ? Character.digit(value[j++], 10) + : 0x0F); + b[i] = (byte) ((h << 4) | l); + } + pin.pin = b; + pin.state = PIN.STATE_RESET; + } + } + } } \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java index 89030894..2e0c54eb 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java @@ -16,7 +16,6 @@ */ package at.gv.egiz.smcc.starcos; -import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.HashMap; @@ -30,6 +29,8 @@ import at.gv.egiz.smcc.CardChannelEmul; import at.gv.egiz.smcc.CardEmul; import at.gv.egiz.smcc.File; import at.gv.egiz.smcc.PIN; +import java.util.ArrayList; +import java.util.List; @SuppressWarnings("restriction") public class STARCOSCardChannelEmul extends CardChannelEmul { @@ -40,14 +41,13 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { * */ protected CardEmul cardEmul; - + + public final List globalFiles = new ArrayList(); public final HashMap globalPins = new HashMap(); - public STARCOSCardChannelEmul(CardEmul cardEmul) { + public STARCOSCardChannelEmul(CardEmul cardEmul, byte[] Glob_PIN, int PIN_STATE) { this.cardEmul = cardEmul; - globalPins.put(KID_PIN_Glob, new PIN(new byte[] { (byte) 0x24, (byte) 0x00, - (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF }, KID_PIN_Glob, 10)); + globalPins.put(KID_PIN_Glob, new PIN(Glob_PIN, KID_PIN_Glob, 10, PIN_STATE)); } @Override @@ -88,6 +88,21 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { } } return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82}); + } else if (globalFiles != null) { + if (command.getP2() != 0x04) { + throw new CardException("Not supported."); + } + for (File file : globalFiles) { + if (Arrays.equals(fid, file.fid)) { + currentFile = file; + byte[] response = new byte[file.fcx.length + 2]; + System.arraycopy(file.fcx, 0, response, 0, file.fcx.length); + response[file.fcx.length] = (byte) 0x90; + response[file.fcx.length + 1] = (byte) 0x00; + return new ResponseAPDU(response); + } + } + return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82}); } else { throw new CardException("Not supported."); } @@ -121,6 +136,23 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { } + protected ResponseAPDU cmdREAD_RECORD(CommandAPDU command) throws CardException { + if (command.getINS() != 0xB2) { + throw new IllegalArgumentException("INS has to be 0xB2"); + } + if (currentFile == null) { + return new ResponseAPDU(new byte[]{ (byte) 0x69, (byte) 0x86 }); + } + if (command.getP1() != 0x01 || command.getP2() != 0x04) { + throw new CardException("Not implemented."); + } + byte[] response = new byte[currentFile.file.length + 2]; + System.arraycopy(currentFile.file, 0, response, 0, currentFile.file.length); + response[currentFile.file.length] = (byte) 0x90; + response[currentFile.file.length + 1] = (byte) 0x00; + return new ResponseAPDU(response); + } + protected ResponseAPDU cmdREAD_BINARY(CommandAPDU command) throws CardException { if (command.getINS() != 0xB0) { @@ -192,6 +224,10 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { case 0xB0: return cmdREAD_BINARY(command); + // READ RECORD + case 0xB2: + return cmdREAD_RECORD(command); + // VERIFY case 0x20: return cmdVERIFY(command); @@ -248,9 +284,15 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { } if (pin != null) { - - if (reference.length == 0) { - return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)}); + + if (reference == null || reference.length == 0) { + if (pin.state == PIN.STATE_PIN_NOTACTIVE) { + return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x84 }); + } else if (pin.state == PIN.STATE_PIN_BLOCKED) { + return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) 0xc0 }); + } else { + return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)}); + } } if (reference.length != 8) { @@ -264,7 +306,7 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { case PIN.STATE_RESET: pin.state = PIN.STATE_PIN_VERIFIED; - + default: pin.kfpc = 10; return new ResponseAPDU(new byte[] { (byte) 0x90, (byte) 0x00 }); @@ -321,7 +363,20 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00}); } - response = verifyPin(0xFF & command.getP2(), data); + PIN pin; + if (currentAppl != null) { + pin = currentAppl.pins.get(command.getP2()); + } else { + pin = globalPins.get(command.getP2()); + } + if (pin.state == PIN.STATE_PIN_NOTACTIVE) { + pin.pin = data; + pin.state = PIN.STATE_RESET; + response = new ResponseAPDU(new byte[] { (byte) 0x90, (byte) 0x00 }); + } else { + // P1 == 0x01 not allowed on active pin (?) + response = new ResponseAPDU(new byte[] { (byte) 0x6A, (byte) 0x86}); + } } else if (command.getP1() == 0x00) { @@ -330,21 +385,22 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { } response = verifyPin(0xFF & command.getP2(), Arrays.copyOf(data, 8)); - + + if (response.getSW() == 0x9000) { + PIN pin; + if (currentAppl != null) { + pin = currentAppl.pins.get(command.getP2()); + } else { + pin = globalPins.get(command.getP2()); + } + pin.pin = Arrays.copyOfRange(data, 8, 16); + pin.state = PIN.STATE_PIN_VERIFIED; + } + } else { return new ResponseAPDU(new byte[] { (byte) 0x6A, (byte) 0x81 }); } - if (response.getSW() == 0x9000) { - PIN pin; - if (currentAppl != null) { - pin = currentAppl.pins.get(command.getP2()); - } else { - pin = globalPins.get(command.getP2()); - } - pin.pin = Arrays.copyOfRange(data, 8, 16); - } - return response; } @@ -353,7 +409,10 @@ public class STARCOSCardChannelEmul extends CardChannelEmul { PIN pin = globalPins.get(kid); if (pin != null) { if (value == null) { - pin.pin = null; +// pin.pin = null; + //TransportPIN +// pin.pin = new byte[] { (byte) 0x24, (byte) 0x12, (byte) 0x34, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + pin.state = PIN.STATE_PIN_NOTACTIVE; } else { byte[] b = new byte[8]; b[0] = (byte) (0x20 | value.length); diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java index 7b2f3fbe..5963fb63 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java @@ -21,30 +21,34 @@ import javax.smartcardio.ATR; import at.gv.egiz.smcc.CardChannelEmul; import at.gv.egiz.smcc.CardEmul; +import at.gv.egiz.smcc.PIN; @SuppressWarnings("restriction") public class STARCOSCardEmul extends CardEmul { - + + public static byte[] DEFAULT_SS_PIN = new byte[] { (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + public static byte[] DEFAULT_Glob_PIN = new byte[] { (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + protected static ATR ATR = new ATR(new byte[] { (byte) 0x3b, (byte) 0xbd, (byte) 0x18, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45, (byte) 0x80, (byte) 0x51, (byte) 0x02, (byte) 0x67, (byte) 0x05, (byte) 0x18, (byte) 0xb1, (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x81, (byte) 0x05, (byte) 0x31 }); - + public STARCOSCardEmul() { - applications.add(new STARCOSApplSichereSignatur((STARCOSCardChannelEmul) channel)); + this(DEFAULT_SS_PIN, DEFAULT_Glob_PIN, PIN.STATE_RESET); + } + + public STARCOSCardEmul(byte[] SS_PIN, byte[] Glob_PIN, int PIN_STATE) { + channel = new STARCOSCardChannelEmul(this, Glob_PIN, PIN_STATE); + applications.add(new STARCOSApplSichereSignatur((STARCOSCardChannelEmul) channel, SS_PIN, PIN_STATE)); applications.add(new STARCOSApplInfobox((STARCOSCardChannelEmul) channel)); - applications.add(new STARCOSApplGewoehnlicheSignatur((STARCOSCardChannelEmul) channel)); + applications.add(new STARCOSApplGewoehnlicheSignatur((STARCOSCardChannelEmul) channel, + STARCOSApplGewoehnlicheSignatur.DST)); } @Override public ATR getATR() { return ATR; } - - @Override - protected CardChannelEmul newCardChannel(CardEmul cardEmul) { - return new STARCOSCardChannelEmul(this); - } - } \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java index b7dc9a0c..154884d4 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java @@ -22,12 +22,9 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import javax.smartcardio.CardChannel; import org.junit.Test; @@ -36,25 +33,20 @@ import at.gv.egiz.smcc.CardEmul; import at.gv.egiz.smcc.CardNotSupportedException; import at.gv.egiz.smcc.CardTerminalEmul; import at.gv.egiz.smcc.CardTest; +import at.gv.egiz.smcc.pin.gui.ChangePINProvider; +import at.gv.egiz.smcc.pin.gui.InvalidChangePINProvider; +import at.gv.egiz.smcc.pin.gui.InvalidPINProvider; import at.gv.egiz.smcc.LockedException; import at.gv.egiz.smcc.NotActivatedException; +import at.gv.egiz.smcc.PIN; import at.gv.egiz.smcc.PINFormatException; import at.gv.egiz.smcc.PINMgmtSignatureCard; import at.gv.egiz.smcc.PINSpec; -import at.gv.egiz.smcc.STARCOSCard; import at.gv.egiz.smcc.SignatureCard; import at.gv.egiz.smcc.SignatureCardException; import at.gv.egiz.smcc.SignatureCardFactory; -import at.gv.egiz.smcc.CardTest.TestChangePINProvider; -import at.gv.egiz.smcc.CardTest.TestPINProvider; -import at.gv.egiz.smcc.PINProvider; +import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider; import at.gv.egiz.smcc.SignatureCard.KeyboxName; -import at.gv.egiz.smcc.acos.A03ApplDEC; -import at.gv.egiz.smcc.acos.A04ApplDEC; -import at.gv.egiz.smcc.acos.A04ApplSIG; -import at.gv.egiz.smcc.acos.ACOSAppl; -import at.gv.egiz.smcc.acos.ACOSApplDEC; -import at.gv.egiz.smcc.acos.ACOSApplSIG; import org.junit.Ignore; public class STARCOSCardTest extends CardTest { @@ -69,7 +61,17 @@ public class STARCOSCardTest extends CardTest { assertTrue(signatureCard instanceof PINMgmtSignatureCard); return signatureCard; } - + + protected SignatureCard createSignatureCard(byte[] SS_PIN, byte[] Glob_PIN, int pinState) + throws CardNotSupportedException { + SignatureCardFactory factory = SignatureCardFactory.getInstance(); + STARCOSCardEmul card = new STARCOSCardEmul(SS_PIN, Glob_PIN, pinState); + SignatureCard signatureCard = factory.createSignatureCard(card, + new CardTerminalEmul(card)); + assertTrue(signatureCard instanceof PINMgmtSignatureCard); + return signatureCard; + } + @Test public void testGetInfoboxIdentityLinkEmpty() throws SignatureCardException, InterruptedException, CardNotSupportedException { @@ -82,7 +84,7 @@ public class STARCOSCardTest extends CardTest { appl.clearInfobox(); byte[] idlink = signatureCard.getInfobox("IdentityLink", - new TestPINProvider(pin), null); + new SMCCTestPINProvider(pin), null); assertNull(idlink); } @@ -98,10 +100,10 @@ public class STARCOSCardTest extends CardTest { STARCOSApplInfobox appl = (STARCOSApplInfobox) card.getApplication(STARCOSAppl.AID_Infobox); appl.setInfoboxHeader((byte) 0xFF); - signatureCard.getInfobox("IdentityLink", new TestPINProvider(pin), null); + signatureCard.getInfobox("IdentityLink", new SMCCTestPINProvider(pin), null); } - + @Test public void testGetCerts() throws SignatureCardException, InterruptedException, CardNotSupportedException { @@ -145,7 +147,7 @@ public class STARCOSCardTest extends CardTest { signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR); } - + @Test public void testSignSichereSignatur() throws SignatureCardException, InterruptedException, CardNotSupportedException, @@ -160,7 +162,7 @@ public class STARCOSCardTest extends CardTest { byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), - KeyboxName.SECURE_SIGNATURE_KEYPAIR, new TestPINProvider(pin), null); + KeyboxName.SECURE_SIGNATURE_KEYPAIR, new SMCCTestPINProvider(pin), null); assertNotNull(signature); @@ -180,12 +182,12 @@ public class STARCOSCardTest extends CardTest { byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), - KeyboxName.CERITIFIED_KEYPAIR, new TestPINProvider(pin), null); + KeyboxName.CERITIFIED_KEYPAIR, new SMCCTestPINProvider(pin), null); assertNotNull(signature); } - + @Test(expected = LockedException.class) public void testSignSichereSignaturInvalidPin() throws SignatureCardException, InterruptedException, CardNotSupportedException, @@ -193,7 +195,7 @@ public class STARCOSCardTest extends CardTest { SignatureCard signatureCard = createSignatureCard(); - TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray()); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray()); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR, @@ -208,7 +210,7 @@ public class STARCOSCardTest extends CardTest { SignatureCard signatureCard = createSignatureCard(); - TestPINProvider pinProvider = new TestPINProvider("1234".toCharArray()); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("1234".toCharArray()); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR, @@ -221,12 +223,9 @@ public class STARCOSCardTest extends CardTest { InterruptedException, CardNotSupportedException, NoSuchAlgorithmException, IOException { - SignatureCard signatureCard = createSignatureCard(); - CardEmul card = (CardEmul) signatureCard.getCard(); - STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur); - appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, null); + SignatureCard signatureCard = createSignatureCard(null, null, PIN.STATE_PIN_BLOCKED); - TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray()); + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray()); assertTrue(pinProvider.getProvided() <= 0); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" @@ -240,68 +239,79 @@ public class STARCOSCardTest extends CardTest { InterruptedException, CardNotSupportedException, NoSuchAlgorithmException, IOException { - SignatureCard signatureCard = createSignatureCard(); - CardEmul card = (CardEmul) signatureCard.getCard(); - STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel(); - channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, null); - - TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray()); + SignatureCard signatureCard = createSignatureCard(null, null, PIN.STATE_PIN_BLOCKED); + + SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("0000".toCharArray()); signatureCard.createSignature(new ByteArrayInputStream("MOCCA" .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR, pinProvider, null); } - + @Test public void testChangePin() throws CardNotSupportedException, LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException { - char[] defaultPin = "123456".toCharArray(); - - PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(); - CardEmul card = (CardEmul) signatureCard.getCard(); - STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel(); - channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, defaultPin); - STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur); - appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, defaultPin); + // set all initial pins to DEFAULT_SS_PIN (123456) + PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard( + STARCOSCardEmul.DEFAULT_SS_PIN, STARCOSCardEmul.DEFAULT_SS_PIN, PIN.STATE_RESET); for (PINSpec pinSpec : signatureCard.getPINSpecs()) { - char[] pin = defaultPin; + char[] pin = "123456".toCharArray(); for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) { - signatureCard.verifyPIN(pinSpec, new TestPINProvider(pin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin)); char[] newPin = new char[i]; Arrays.fill(newPin, '0'); signatureCard - .changePIN(pinSpec, new TestChangePINProvider(pin, newPin)); - signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin)); + .changePIN(pinSpec, new ChangePINProvider(pin, newPin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin)); pin = newPin; } } } @Test - public void testVerifyInvalidPin() throws CardNotSupportedException, + @Override + public void testActivatePin() throws CardNotSupportedException, LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException { - char[] defaultPin = "123456".toCharArray(); + PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard( + null, null, PIN.STATE_PIN_NOTACTIVE); + + for (PINSpec pinSpec : signatureCard.getPINSpecs()) { + + char[] pin = "1234567890".substring(0, pinSpec.getMinLength()).toCharArray(); + + boolean notActive = false; + try { + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin)); + } catch (NotActivatedException ex) { + notActive = true; + } + assertTrue(notActive); + + signatureCard.activatePIN(pinSpec, new ChangePINProvider(null, pin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin)); + } + } + + @Test + public void testVerifyInvalidPin() throws CardNotSupportedException, + LockedException, NotActivatedException, CancelledException, + PINFormatException, SignatureCardException, InterruptedException { PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(); - CardEmul card = (CardEmul) signatureCard.getCard(); - STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel(); - channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, defaultPin); - STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur); - appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, defaultPin); for (PINSpec pinSpec : signatureCard.getPINSpecs()) { char[] invalidPin = "999999".toCharArray(); int numInvalidTries = 2; - TestInvalidPINProvider invalidPinProvider = new TestInvalidPINProvider(invalidPin, numInvalidTries); + InvalidPINProvider invalidPinProvider = new InvalidPINProvider(invalidPin, numInvalidTries); try { signatureCard.verifyPIN(pinSpec, invalidPinProvider); } catch (CancelledException ex) { @@ -315,21 +325,15 @@ public class STARCOSCardTest extends CardTest { public void testChangeInvalidPin() throws CardNotSupportedException, LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException { - char[] defaultPin = "123456".toCharArray(); PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(); - CardEmul card = (CardEmul) signatureCard.getCard(); - STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel(); - channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, defaultPin); - STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur); - appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, defaultPin); - + for (PINSpec pinSpec : signatureCard.getPINSpecs()) { char[] invalidPin = "999999".toCharArray(); int numInvalidTries = 2; - TestInvalidChangePINProvider invalidPinProvider = - new TestInvalidChangePINProvider(invalidPin, defaultPin, numInvalidTries); + InvalidChangePINProvider invalidPinProvider = + new InvalidChangePINProvider(invalidPin, invalidPin, numInvalidTries); try { signatureCard.changePIN(pinSpec, invalidPinProvider); diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java new file mode 100644 index 00000000..dc6836ae --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java @@ -0,0 +1,46 @@ +/* + * Copyright 2008 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.starcos; + +import at.gv.egiz.smcc.CardEmul; +import at.gv.egiz.smcc.File; +import at.gv.egiz.smcc.PIN; + +/** + * + * @author clemens + */ +public class STARCOSG3CardChannelEmul extends STARCOSCardChannelEmul { + + public STARCOSG3CardChannelEmul(CardEmul cardEmul, byte[] Glob_PIN, int PIN_STATE) { + super(cardEmul, Glob_PIN, PIN_STATE); + + // G3 version file + byte[] versionFileFID = new byte[]{(byte) 0x00, (byte) 0x32}; + byte[] versionFile = new byte[]{ + (byte) 0xa5, (byte) 0x0e, (byte) 0x53, (byte) 0x02, (byte) 0x01, (byte) 0x20, (byte) 0x54, (byte) 0x08, + (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0x70, (byte) 0x01}; + byte[] versionFileFCX = new byte[]{ + (byte) 0x62, (byte) 0x1a, (byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x14, (byte) 0x82, (byte) 0x05, + (byte) 0x44, (byte) 0x41, (byte) 0x00, (byte) 0x14, (byte) 0x01, (byte) 0x83, (byte) 0x02, (byte) 0x00, + (byte) 0x32, (byte) 0x88, (byte) 0x01, (byte) 0xd8, (byte) 0x8a, (byte) 0x01, (byte) 0x05, (byte) 0xa1, + (byte) 0x03, (byte) 0x8b, (byte) 0x01, (byte) 0x03}; + + globalFiles.add(new File(versionFileFID, versionFile, versionFileFCX)); + + } + } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java new file mode 100644 index 00000000..7583b3ad --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java @@ -0,0 +1,57 @@ +/* + * Copyright 2008 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.starcos; + +import at.gv.egiz.smcc.CardEmul; +import javax.smartcardio.ATR; + +import at.gv.egiz.smcc.PIN; + +@SuppressWarnings("restriction") +public class STARCOSG3CardEmul extends CardEmul { + + public static byte[] TRANSPORT_SS_PIN = new byte[] { (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + public static byte[] TRANSPORT_Glob_PIN = new byte[] { (byte) 0x24, (byte) 0x12, (byte) 0x34, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + + public static byte[] DEFAULT_SS_PIN = TRANSPORT_SS_PIN; + public static byte[] DEFAULT_Glob_PIN = new byte[] { (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + + protected static ATR ATR = new ATR(new byte[] { + (byte) 0x3b, (byte) 0xbd, (byte) 0x18, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45, + (byte) 0x80, (byte) 0x51, (byte) 0x02, (byte) 0x67, (byte) 0x05, (byte) 0x18, (byte) 0xb1, (byte) 0x02, + (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x81, (byte) 0x05, (byte) 0x31 + }); + + public STARCOSG3CardEmul(byte[] SS_PIN, byte[] Glob_PIN, int PIN_STATE){ + channel = new STARCOSG3CardChannelEmul(this, Glob_PIN, PIN_STATE); + applications.add(new STARCOSApplSichereSignatur((STARCOSCardChannelEmul) channel, + SS_PIN, PIN_STATE)); + applications.add(new STARCOSApplInfobox((STARCOSCardChannelEmul) channel)); + applications.add(new STARCOSApplGewoehnlicheSignatur((STARCOSCardChannelEmul) channel, + STARCOSApplGewoehnlicheSignatur.DST_G3)); + } + + + public STARCOSG3CardEmul() { + this(DEFAULT_SS_PIN, DEFAULT_Glob_PIN, PIN.STATE_RESET); + } + + @Override + public ATR getATR() { + return ATR; + } +} diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java new file mode 100644 index 00000000..06744c82 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java @@ -0,0 +1,119 @@ +/* +* Copyright 2008 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.starcos; + +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + + +import org.junit.Test; + +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.CardEmul; +import at.gv.egiz.smcc.CardNotSupportedException; +import at.gv.egiz.smcc.CardTerminalEmul; +import at.gv.egiz.smcc.CardTest; +import at.gv.egiz.smcc.pin.gui.ChangePINProvider; +import at.gv.egiz.smcc.LockedException; +import at.gv.egiz.smcc.NotActivatedException; +import at.gv.egiz.smcc.PIN; +import at.gv.egiz.smcc.PINFormatException; +import at.gv.egiz.smcc.PINMgmtSignatureCard; +import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.SignatureCard; +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.SignatureCardFactory; +import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider; +import org.junit.Ignore; + +public class STARCOSG3CardTest extends CardTest { + + @Override + protected SignatureCard createSignatureCard() + throws CardNotSupportedException { + SignatureCardFactory factory = SignatureCardFactory.getInstance(); + STARCOSG3CardEmul card = new STARCOSG3CardEmul(); + SignatureCard signatureCard = factory.createSignatureCard(card, + new CardTerminalEmul(card)); + assertTrue(signatureCard instanceof PINMgmtSignatureCard); + return signatureCard; + } + + protected SignatureCard createSignatureCard(byte[] SS_PIN, byte[] Glob_PIN, int pinState) + throws CardNotSupportedException { + SignatureCardFactory factory = SignatureCardFactory.getInstance(); + STARCOSG3CardEmul card = new STARCOSG3CardEmul(SS_PIN, Glob_PIN, pinState); + SignatureCard signatureCard = factory.createSignatureCard(card, + new CardTerminalEmul(card)); + assertTrue(signatureCard instanceof PINMgmtSignatureCard); + return signatureCard; + } + + @Test + public void testChangePin() throws CardNotSupportedException, + LockedException, NotActivatedException, CancelledException, + PINFormatException, SignatureCardException, InterruptedException { + + PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard( + STARCOSG3CardEmul.DEFAULT_SS_PIN, STARCOSG3CardEmul.DEFAULT_SS_PIN, PIN.STATE_RESET); + + for (PINSpec pinSpec : signatureCard.getPINSpecs()) { + + char[] pin = "123456".toCharArray(); + + for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) { + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin)); + char[] newPin = new char[i]; + Arrays.fill(newPin, '0'); + signatureCard + .changePIN(pinSpec, new ChangePINProvider(pin, newPin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin)); + pin = newPin; + } + } + } + + @Test + @Override + public void testActivatePin() throws CardNotSupportedException, + LockedException, NotActivatedException, CancelledException, + PINFormatException, SignatureCardException, InterruptedException { + + PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard( + STARCOSG3CardEmul.TRANSPORT_SS_PIN, STARCOSG3CardEmul.TRANSPORT_SS_PIN, PIN.STATE_PIN_NOTACTIVE); + + for (PINSpec pinSpec : signatureCard.getPINSpecs()) { + + char[] pin = "123456789".substring(0, pinSpec.getMinLength()).toCharArray(); + char[] transportPIN = "123456".toCharArray(); + + boolean notActive = false; + try { + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin)); + } catch (NotActivatedException ex) { + notActive = true; + } + assertTrue(notActive); + + signatureCard.activatePIN(pinSpec, new ChangePINProvider(transportPIN, pin)); + signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin)); + } + } + + +} -- cgit v1.2.3