summaryrefslogtreecommitdiff
path: root/smcc/src/main
diff options
context:
space:
mode:
authorclemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>2010-01-05 10:06:47 +0000
committerclemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>2010-01-05 10:06:47 +0000
commit3da4655d011dfc2f04f9e4ac28b38aee42d01bc0 (patch)
treed9b524ca4ccfd6e48573dfecf5191ccba48278af /smcc/src/main
parentecc11bdb13ae27385486ad1c944ee01ffd0440e7 (diff)
downloadmocca-3da4655d011dfc2f04f9e4ac28b38aee42d01bc0.tar.gz
mocca-3da4655d011dfc2f04f9e4ac28b38aee42d01bc0.tar.bz2
mocca-3da4655d011dfc2f04f9e4ac28b38aee42d01bc0.zip
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
Diffstat (limited to 'smcc/src/main')
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java44
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java14
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java11
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ITCard.java11
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java19
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java19
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java11
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java38
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java208
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SWCard.java106
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java9
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java36
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java (renamed from smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java)20
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java42
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java (renamed from smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java)8
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java92
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java106
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java703
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java128
19 files changed, 1344 insertions, 281 deletions
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
index 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
@@ -81,11 +80,6 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
@Override
- public CCID getReader() {
- return reader;
- }
-
- @Override
public void setLocale(Locale locale) {
if (locale == null) {
throw new NullPointerException("Locale must not be set to 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/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 <clemens.orthacker@iaik.tugraz.at>
*/
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 <clemens.orthacker@iaik.tugraz.at>
*/
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/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/ChangePINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java
index 41010551..36f0097d 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java
@@ -14,13 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package at.gv.egiz.smcc;
+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
+ * <ul>
+ * <li> current pin and new pin (change pin)
+ * <li> new pin (pin activation, no current pin)
+ * <li> puk and new pin (probably verify only?)
+ * </ul>
* @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
*/
-public interface ChangePINProvider extends PINProvider {
+public interface ModifyPINProvider {
/**
*
@@ -30,7 +39,10 @@ public interface ChangePINProvider extends PINProvider {
* @throws at.gv.egiz.smcc.CancelledException if cancelled by user
* @throws java.lang.InterruptedException
*/
- public char[] provideOldPIN(PINSpec spec, int retries)
+ 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/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java
index 5c294b5b..3bf49888 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java
@@ -14,7 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package at.gv.egiz.smcc;
+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.
@@ -39,7 +43,7 @@ public interface PINProvider {
* @throws at.gv.egiz.smcc.CancelledException
* @throws java.lang.InterruptedException
*/
- public char[] providePIN(PINSpec spec, int retries)
+ 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 <clemens.orthacker@iaik.tugraz.at>
+ */
+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 <clemens.orthacker@iaik.tugraz.at>
+ */
+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 <clemens.orthacker@iaik.tugraz.at>
+ */
+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<Byte, Integer> features;
+ protected boolean VERIFY, MODIFY, VERIFY_DIRECT, MODIFY_DIRECT;
+
+ public PinpadCardReader(CardTerminal ct, Map<Byte, Integer> 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 <clemens.orthacker@iaik.tugraz.at>
+ */
+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<Byte, Integer> 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<Byte, Integer> queryFeatures(Card icc) {
+ Map<Byte, Integer> features = new HashMap<Byte, Integer>();
+
+ 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;
+ }
+
+}