summaryrefslogtreecommitdiff
path: root/smcc
diff options
context:
space:
mode:
Diffstat (limited to 'smcc')
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java30
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java410
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java352
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java39
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java26
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java479
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SWCard.java36
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java42
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java2
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java39
-rw-r--r--smcc/src/test/resources/log4j.properties2
11 files changed, 1098 insertions, 359 deletions
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java
new file mode 100644
index 00000000..9fca6ab9
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java
@@ -0,0 +1,30 @@
+/*
+ * 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 <clemens.orthacker@iaik.tugraz.at>
+ */
+public class ACOS04Card extends ACOSCard {
+
+ public ACOS04Card() {
+ pinSpecs.remove(PINSPEC_INF);
+ }
+
+}
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 c2c62fd8..01b9155b 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
@@ -29,9 +29,10 @@
package at.gv.egiz.smcc;
import at.gv.egiz.smcc.util.SMCCHelper;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
import java.nio.charset.Charset;
-import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
@@ -100,9 +101,9 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
(byte) 0x01 // RSA // TODO: Not verified yet
};
- private static final int PINSPEC_INF = 0;
- private static final int PINSPEC_DEC = 1;
- private static final int PINSPEC_SIG = 2;
+ protected static final int PINSPEC_INF = 0;
+ protected static final int PINSPEC_DEC = 1;
+ protected static final int PINSPEC_SIG = 2;
public ACOSCard() {
super("at/gv/egiz/smcc/ACOSCard");
@@ -179,15 +180,12 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
//new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"));
int retries = -1;
- String pin = null;
+ char[] pin = null;
boolean pinRequiered = false;
do {
if (pinRequiered) {
pin = provider.providePIN(spec, retries);
- if (pin == null) {
- throw new CancelledException();
- }
}
try {
getCard().beginExclusive();
@@ -234,20 +232,17 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
//new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));
int retries = -1;
- String pin = null;
+ char[] pin = null;
do {
pin = provider.providePIN(spec, retries);
- if (pin == null) {
- throw new CancelledException();
- }
try {
getCard().beginExclusive();
// SELECT DF
selectFileFID(DF_SIG);
// VERIFY
- retries = verifyPIN(pin, KID_PIN_SIG);
+ retries = verifyPIN(KID_PIN_SIG, pin);
if (retries != -1) {
throw new VerificationFailedException(retries);
}
@@ -259,7 +254,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
return psoComputDigitalSiganture();
} catch (SecurityStatusNotSatisfiedException e) {
- retries = verifyPIN(null, KID_PIN_SIG);
+ retries = verifyPIN(KID_PIN_SIG);
} catch (VerificationFailedException e) {
retries = e.getRetries();
} finally {
@@ -276,15 +271,12 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
//new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name"));
int retries = -1;
- String pin = null;
- boolean pinRequiered = false;
+ char[] pin = null;
+ boolean pinRequired = false;
do {
- if (pinRequiered) {
+ if (pinRequired) {
pin = provider.providePIN(spec, retries);
- if (pin == null) {
- throw new CancelledException();
- }
}
try {
getCard().beginExclusive();
@@ -292,7 +284,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
// SELECT DF
selectFileFID(DF_DEC);
// VERIFY
- retries = verifyPIN(pin, KID_PIN_DEC);
+ retries = verifyPIN(KID_PIN_DEC, pin);
if (retries != -1) {
throw new VerificationFailedException(retries);
}
@@ -304,10 +296,10 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
} catch (FileNotFoundException e) {
throw new NotActivatedException();
} catch (SecurityStatusNotSatisfiedException e) {
- pinRequiered = true;
- retries = verifyPIN(null, KID_PIN_DEC);
+ pinRequired = true;
+ retries = verifyPIN(KID_PIN_DEC);
} catch (VerificationFailedException e) {
- pinRequiered = true;
+ pinRequired = true;
retries = e.getRetries();
} finally {
getCard().endExclusive();
@@ -328,48 +320,16 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
+ ////////////////////////////////////////////////////////////////////////
+ // PROTECTED METHODS (assume exclusive card access)
+ ////////////////////////////////////////////////////////////////////////
+
protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,
0x00, fid, 256));
}
- @Override
- protected int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException {
-
- CardChannel channel = getCardChannel();
-
- ResponseAPDU resp;
- try {
- if (pin != null) {
- resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, encodePINBlock(pin)), false);
- } else {
- //TODO this is not supported
- resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid), false);
- }
- } catch (CardException ex) {
- log.error("smart card communication failed: " + ex.getMessage());
- throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
- }
-
- //6A 00 (falshe P1/P2) nicht in contextAID
- //69 85 (nutzungsbedingungen nicht erfüllt) in DF_Sig und nicht sigpin
-
- if (resp.getSW() == 0x63c0) {
- throw new LockedException("PIN locked.");
- } else if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) {
- // return number of possible retries
- return resp.getSW2() & 0x0f;
- } else if (resp.getSW() == 0x6983) {
- throw new NotActivatedException();
- } else if (resp.getSW() == 0x9000) {
- return -1;
- } else {
- throw new SignatureCardException("Failed to verify pin: SW="
- + Integer.toHexString(resp.getSW()) + ".");
- }
- }
-
private void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, p1,
@@ -426,92 +386,294 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
}
- @Override
- public String toString() {
- return "a-sign premium";
- }
-
/**
- * ASCII encoded pin, padded with 0x00
- * @param pin
- * @return a 8 byte pin block
+ *
+ * @param kid
+ * @return -1
*/
- private byte[] encodePINBlock(String pin) {
- byte[] asciiPIN = pin.getBytes(Charset.forName("ASCII"));
- byte[] encodedPIN = new byte[8];
- System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length,
- encodedPIN.length));
-// System.out.println("ASCII encoded PIN block: " + SMCCHelper.toString(encodedPIN));
- return encodedPIN;
+ @Override
+ protected int verifyPIN(byte kid) {
+ log.debug("VERIFY PIN without PIN BLOCK not supported by ACOS");
+ return -1;
}
@Override
- public void activatePIN(PINSpec pinSpec, String pin) throws SignatureCardException {
- throw new SignatureCardException("PIN activation not supported by this card");
+ protected int verifyPIN(byte kid, char[] pin)
+ throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
+ try {
+ byte[] sw;
+ if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+ log.debug("verify PIN on IFD");
+ sw = transmitControlCommand(
+ ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT),
+ getPINVerifyStructure(kid));
+// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
+ } else {
+ byte[] pinBlock = encodePINBlock(pin);
+ CardChannel channel = getCardChannel();
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false);
+ sw = new byte[2];
+ sw[0] = (byte) resp.getSW1();
+ sw[1] = (byte) resp.getSW2();
+ }
+
+ //6A 00 (falshe P1/P2) nicht in contextAID
+ //69 85 (nutzungsbedingungen nicht erfüllt) in DF_Sig und nicht sigpin
+
+ if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
+ return -1;
+ } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
+ throw new LockedException("[63:c0]");
+ } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
+ return sw[1] & 0x0f;
+ } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
+ //Authentisierungsmethode gesperrt
+ throw new NotActivatedException("[69:83]");
+// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
+// //referenzierte Daten sind reversibel gesperrt (invalidated)
+// throw new NotActivatedException("[69:84]");
+// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
+// //Benutzungsbedingungen nicht erfüllt
+// throw new NotActivatedException("[69:85]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
+ throw new TimeoutException("[64:00]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
+ throw new CancelledException("[64:01]");
+ }
+ log.error("Failed to verify pin: SW="
+ + SMCCHelper.toString(sw));
+ throw new SignatureCardException(SMCCHelper.toString(sw));
+
+ } catch (CardException ex) {
+ log.error("smart card communication failed: " + ex.getMessage());
+ throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
+ }
}
/**
* SCARD_E_NOT_TRANSACTED inf/dec PIN not active (pcsc crash)
- * @param pinSpec
- * @param oldPIN
- * @param newPIN
+ * @param kid
+ * @param oldPin
+ * @param newPin
+ * @return
* @throws at.gv.egiz.smcc.LockedException
- * @throws at.gv.egiz.smcc.VerificationFailedException
* @throws at.gv.egiz.smcc.NotActivatedException
* @throws at.gv.egiz.smcc.SignatureCardException
*/
@Override
- public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN)
- throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException {
- Card icc = getCard();
+ protected int changePIN(byte kid, char[] oldPin, char[] newPin)
+ throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
try {
- icc.beginExclusive();
- CardChannel channel = icc.getBasicChannel();
-
- if (pinSpec.getContextAID() != null) {
- ResponseAPDU responseAPDU = transmit(channel,
- new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID()));
- if (responseAPDU.getSW() != 0x9000) {
- icc.endExclusive();
- String msg = "Select AID " + SMCCHelper.toString(pinSpec.getContextAID()) +
- ": SW=" + Integer.toHexString(responseAPDU.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
- }
- }
-
- byte[] cmd = new byte[16];
- System.arraycopy(encodePINBlock(oldPIN), 0, cmd, 0, 8);
- System.arraycopy(encodePINBlock(newPIN), 0, cmd, 8, 8);
+ byte[] sw;
+ if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+ log.debug("modify PIN on IFD");
+ sw = transmitControlCommand(
+ ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT),
+ getPINModifyStructure(kid));
+// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
+ } else {
+ byte[] cmd = new byte[16];
+ System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8);
+ System.arraycopy(encodePINBlock(newPin), 0, cmd, 8, 8);
- ResponseAPDU responseAPDU = transmit(channel,
- new CommandAPDU(0x00, 0x24, 0x00, pinSpec.getKID(), cmd), false);
+ CardChannel channel = getCardChannel();
- icc.endExclusive();
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0x24, 0x00, kid, cmd), false);
- log.debug("change pin returned SW=" + Integer.toHexString(responseAPDU.getSW()));
+ sw = new byte[2];
+ sw[0] = (byte) resp.getSW1();
+ sw[1] = (byte) resp.getSW2();
+ }
- if (responseAPDU.getSW() == 0x63c0) {
- log.error(pinSpec.getLocalizedName() + " locked");
- throw new LockedException();
- } else if (responseAPDU.getSW1() == 0x63 && responseAPDU.getSW2() >> 4 == 0xc) {
- int retries = responseAPDU.getSW2() & 0x0f;
- log.error("wrong " + pinSpec.getLocalizedName() + ", " + retries + " retries");
- throw new VerificationFailedException(retries);
- } else if (responseAPDU.getSW() == 0x6983) {
+ // activates pin (newPIN) if not active
+ if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
+ return -1;
+ } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
+ throw new LockedException("[63:c0]");
+ } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
+ return sw[1] & 0x0f;
+ } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
+ //Authentisierungsmethode gesperrt
// sig-pin only (card not transacted for inf/dec pin)
- log.error(pinSpec.getLocalizedName() + " not activated");
- throw new NotActivatedException();
- } else if (responseAPDU.getSW() != 0x9000) {
- String msg = "Failed to change " + pinSpec.getLocalizedName() +
- ": SW=" + Integer.toHexString(responseAPDU.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
+ throw new NotActivatedException("[69:83]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
+ throw new TimeoutException("[64:00]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
+ throw new CancelledException("[64:01]");
}
+ log.error("Failed to change pin: SW="
+ + SMCCHelper.toString(sw));
+ throw new SignatureCardException(SMCCHelper.toString(sw));
+
} catch (CardException ex) {
- log.error("Failed to change " + pinSpec.getLocalizedName() +
- ": " + ex.getMessage());
- throw new SignatureCardException(ex.getMessage(), ex);
+ log.error("smart card communication failed: " + ex.getMessage());
+ throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
}
}
+
+ /**
+ * throws SignatureCardException (PIN activation not supported by ACOS)
+ * @throws at.gv.egiz.smcc.SignatureCardException
+ */
+ @Override
+ public void activatePIN(byte kid, char[] pin)
+ throws SignatureCardException {
+ log.error("ACTIVATE PIN not supported by ACOS");
+ throw new SignatureCardException("PIN activation not supported by this card");
+ }
+
+ /**
+ * ASCII encoded pin, padded with 0x00
+ * @param pin
+ * @return a 8 byte pin block
+ */
+ @Override
+ protected byte[] encodePINBlock(char[] pin) {
+// byte[] asciiPIN = new String(pin).getBytes(Charset.forName("ASCII"));
+ CharBuffer chars = CharBuffer.wrap(pin);
+ ByteBuffer bytes = Charset.forName("ASCII").encode(chars);
+ byte[] asciiPIN = bytes.array();
+ byte[] encodedPIN = new byte[8];
+ System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length,
+ encodedPIN.length));
+// System.out.println("ASCII encoded PIN block: " + SMCCHelper.toString(encodedPIN));
+ return encodedPIN;
+ }
+
+ private byte[] getPINVerifyStructure(byte kid) {
+
+ byte bTimeOut = (byte) 00; // Default time out
+ byte bTimeOut2 = (byte) 00; // Default time out
+ byte bmFormatString = (byte) 0x82; // 1 0001 0 01
+ // ^------------ System unit = byte
+ // ^^^^------- PIN position in the frame = 1 byte
+ // ^----- PIN justification left
+ // ^^-- BCD format
+ // 1 0000 0 10
+ // ^^-- ASCII format
+ byte bmPINBlockString = (byte) 0x08; // 0100 0111
+ // ^^^^--------- PIN length size: 4 bits
+ // ^^^^---- Length PIN = 7 bytes
+ byte bmPINLengthFormat = (byte) 0x04; // 000 0 0100
+ // ^-------- System bit units is bit
+ // ^^^^--- PIN length is at the 4th position bit
+ byte wPINMaxExtraDigitL = (byte) 0x04; // Max=4 digits
+ byte wPINMaxExtraDigitH = (byte) 0x04; // Min=4 digits
+ byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
+ byte bNumberMessage = (byte) 0x00; // No message
+ byte wLangIdL = (byte) 0x0C; // - English?
+ byte wLangIdH = (byte) 0x04; // \
+ byte bMsgIndex = (byte) 0x00; // Default Msg
+
+ byte[] apdu = new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08, // CLA INS P1 P2 LC
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Data
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 // Data
+ };
+
+ int offset = 0;
+ byte[] pinVerifyStructure = new byte[offset + 19 + apdu.length];
+ pinVerifyStructure[offset++] = bTimeOut;
+ pinVerifyStructure[offset++] = bTimeOut2;
+ pinVerifyStructure[offset++] = bmFormatString;
+ pinVerifyStructure[offset++] = bmPINBlockString;
+ pinVerifyStructure[offset++] = bmPINLengthFormat;
+ pinVerifyStructure[offset++] = wPINMaxExtraDigitL;
+ pinVerifyStructure[offset++] = wPINMaxExtraDigitH;
+ pinVerifyStructure[offset++] = bEntryValidationCondition;
+ pinVerifyStructure[offset++] = bNumberMessage;
+ pinVerifyStructure[offset++] = wLangIdL;
+ pinVerifyStructure[offset++] = wLangIdH;
+ pinVerifyStructure[offset++] = bMsgIndex;
+
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+
+ pinVerifyStructure[offset++] = (byte) apdu.length;
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+ System.arraycopy(apdu, 0, pinVerifyStructure, offset, apdu.length);
+
+ return pinVerifyStructure;
+ }
+
+ public byte[] getPINModifyStructure(byte kid) {
+
+ byte bTimeOut = (byte) 00; // Default time out
+ byte bTimeOut2 = (byte) 00; // Default time out
+ byte bmFormatString = (byte) 0x82; // 1 0001 0 01
+ // ^------------ System unit = byte
+ // ^^^^------- PIN position in the frame = 1 byte
+ // ^----- PIN justification left
+ // ^^-- BCD format
+ // 1 0000 0 10
+ // ^^-- ASCII format
+ byte bmPINBlockString = (byte) 0x08; // 0100 0111
+ // ^^^^--------- PIN length size: 4 bits
+ // ^^^^---- Length PIN = 7 bytes
+ byte bmPINLengthFormat = (byte) 0x00; // 000 0 0100
+ // ^-------- System bit units is bit
+ // ^^^^--- PIN length is at the 4th position bit
+ byte bInsertionOffsetOld = (byte) 0x00; // insertion position offset in bytes
+ byte bInsertionOffsetNew = (byte) 0x00; // insertion position offset in bytes
+ byte wPINMaxExtraDigitL = (byte) 0x04; // Min=4 digits
+ byte wPINMaxExtraDigitH = (byte) 0x04; // Max=12 digits
+ byte bConfirmPIN = (byte) 0x00; // ??? need for confirm pin
+ byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
+ byte bNumberMessage = (byte) 0x00; // No message
+ byte wLangIdL = (byte) 0x0C; // - English?
+ byte wLangIdH = (byte) 0x04; // \
+ byte bMsgIndex1 = (byte) 0x00; // Default Msg
+ byte bMsgIndex2 = (byte) 0x00; // Default Msg
+ byte bMsgIndex3 = (byte) 0x00; // Default Msg
+
+ byte[] apdu = new byte[] {
+ (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10, // CLA INS P1 P2 LC
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // ...
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff // ...
+ };
+
+ int offset = 0;
+ byte[] pinModifyStructure = new byte[offset + 24 + apdu.length];
+ pinModifyStructure[offset++] = bTimeOut;
+ pinModifyStructure[offset++] = bTimeOut2;
+ pinModifyStructure[offset++] = bmFormatString;
+ pinModifyStructure[offset++] = bmPINBlockString;
+ pinModifyStructure[offset++] = bmPINLengthFormat;
+ pinModifyStructure[offset++] = bInsertionOffsetOld;
+ pinModifyStructure[offset++] = bInsertionOffsetNew;
+ pinModifyStructure[offset++] = wPINMaxExtraDigitL;
+ pinModifyStructure[offset++] = wPINMaxExtraDigitH;
+ pinModifyStructure[offset++] = bConfirmPIN;
+ pinModifyStructure[offset++] = bEntryValidationCondition;
+ pinModifyStructure[offset++] = bNumberMessage;
+ pinModifyStructure[offset++] = wLangIdL;
+ pinModifyStructure[offset++] = wLangIdH;
+ pinModifyStructure[offset++] = bMsgIndex1;
+ pinModifyStructure[offset++] = bMsgIndex2;
+ pinModifyStructure[offset++] = bMsgIndex3;
+
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+
+ pinModifyStructure[offset++] = (byte) apdu.length;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ System.arraycopy(apdu, 0, pinModifyStructure, offset, apdu.length);
+
+ return pinModifyStructure;
+ }
+
+ @Override
+ public String toString() {
+ return "a-sign premium";
+ }
}
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 39952bb9..6587aaf9 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
@@ -33,12 +33,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.ResourceBundle;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
@@ -54,6 +54,14 @@ public abstract class AbstractSignatureCard implements SignatureCard {
private static Log log = LogFactory.getLog(AbstractSignatureCard.class);
+ static final short GET_FEATURE_REQUEST = 3400;
+
+ private static int getCtrlCode(short function) {
+ return 0x310000 | ((0xFFFF & function) << 2);
+ }
+
+ protected Map<Byte, Long> ifdCtrlCmds;
+
protected List<PINSpec> pinSpecs = new ArrayList<PINSpec>();
private ResourceBundle i18n;
@@ -106,11 +114,14 @@ public abstract class AbstractSignatureCard implements SignatureCard {
*/
protected byte[] selectFileAID(byte[] dfName) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04,
- 0x00, dfName, 256));
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0xA4, 0x04, 0x00, dfName, 256));
+// new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, dfName));
if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("Failed to select application AID="
- + toString(dfName) + ": SW=" + Integer.toHexString(resp.getSW()) + ".");
+ String msg = "Failed to select application AID=" + SMCCHelper.toString(dfName) +
+ ": SW=" + Integer.toHexString(resp.getSW());
+ log.error(msg);
+ throw new SignatureCardException(msg);
} else {
return resp.getBytes();
}
@@ -119,10 +130,63 @@ public abstract class AbstractSignatureCard implements SignatureCard {
protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException,
SignatureCardException;
- protected abstract int verifyPIN(String pin, byte kid)
+ /**
+ * VERIFY APDU without PIN BLOCK
+ * Not supported by ACOS cards (and GemPC Pinpad?)
+ * @param kid
+ * @return the number of possible tries until card is blocked or -1 if unknown
+ * (ACOS does not support this VERIFY APDU type)
+ * @throws at.gv.egiz.smcc.LockedException
+ * @throws at.gv.egiz.smcc.NotActivatedException
+ * @throws at.gv.egiz.smcc.SignatureCardException
+ */
+ protected abstract int verifyPIN(byte kid)
throws LockedException, NotActivatedException, SignatureCardException;
-
+ /**
+ * VERIFY APDU with PIN BLOCK
+ * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty.
+ * @param kid
+ * @param pin to be encoded in the PIN BLOCK
+ * @return -1 if VERIFY PIN was successful, or the number of possible retries
+ * @throws at.gv.egiz.smcc.LockedException
+ * @throws at.gv.egiz.smcc.NotActivatedException
+ * @throws at.gv.egiz.smcc.SignatureCardException
+ */
+ protected abstract int verifyPIN(byte kid, char[] pin)
+ throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException;
+
+ /**
+ * CHANGE(?) APDU
+ * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty.
+ * @param kid
+ * @param pin
+ * @throws at.gv.egiz.smcc.SignatureCardException if activation fails
+ */
+ protected abstract void activatePIN(byte kid, char[] pin)
+ throws CancelledException, TimeoutException, SignatureCardException;
+
+ /**
+ * CHANGE(?) APDU
+ * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty.
+ * @param kid
+ * @param pin
+ * @return -1 if CHANGE PIN was successful, or the number of possible retries
+ * @throws at.gv.egiz.smcc.SignatureCardException if change fails
+ */
+ protected abstract int changePIN(byte kid, char[] oldPin, char[] newPin)
+ throws CancelledException, TimeoutException, SignatureCardException;
+
+ /**
+ * encode the pin as needed in VERIFY/CHANGE APDUs
+ * @param pin
+ * @return
+ * @throws at.gv.egiz.smcc.SignatureCardException if the provided pin does
+ * not meet the restrictions imposed by the encoding (not the pinSpec!),
+ * such as maximum Length
+ */
+ protected abstract byte[] encodePINBlock(char[] pin) throws SignatureCardException;
+
protected byte[] readRecord(int recordNumber) throws SignatureCardException, CardException {
return readRecord(getCardChannel(), recordNumber);
}
@@ -295,7 +359,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
* @throws SignatureCardException
* @throws CardException
*/
- protected byte[] readTLVFile(byte[] aid, byte[] ef, String pin, byte kid, int maxLength)
+ protected byte[] readTLVFile(byte[] aid, byte[] ef, char[] pin, byte kid, int maxLength)
throws SignatureCardException, InterruptedException, CardException {
@@ -318,7 +382,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
// VERIFY
if (pin != null) {
- int retries = verifyPIN(pin, kid);
+ int retries = verifyPIN(kid, pin);
if (retries != -1) {
throw new VerificationFailedException(retries);
}
@@ -388,6 +452,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
ifs_ = 0xFF & atr.getBytes()[6];
log.trace("Setting IFS (information field size) to " + ifs_);
}
+ ifdCtrlCmds = queryIFDFeatures();
}
@Override
@@ -446,39 +511,266 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
@Override
- public int verifyPIN(PINSpec pinSpec, String pin) throws LockedException, NotActivatedException, SignatureCardException {
-
- Card icc = getCard();
+ public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException {
try {
- icc.beginExclusive();
- CardChannel channel = icc.getBasicChannel();
+ getCard().beginExclusive();
if (pinSpec.getContextAID() != null) {
- ResponseAPDU responseAPDU = transmit(channel,
- new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID()));
- if (responseAPDU.getSW() != 0x9000) {
- icc.endExclusive();
- String msg = "Failed to verify PIN " +
- SMCCHelper.toString(new byte[]{pinSpec.getKID()}) +
- ": Failed to verify AID " +
- SMCCHelper.toString(pinSpec.getContextAID()) +
- ": " + SMCCHelper.toString(responseAPDU.getBytes());
- log.error(msg);
- throw new SignatureCardException(msg);
- }
+ selectFileAID(pinSpec.getContextAID());
}
- return verifyPIN(pin, pinSpec.getKID());
+
+ int retries = verifyPIN(pinSpec.getKID());
+ do {
+ char[] pin = pinProvider.providePIN(pinSpec, retries);
+ retries = verifyPIN(pinSpec.getKID(), pin);
+ } while (retries > 0);
+ //return on -1, 0 never reached: verifyPIN throws LockedEx
} catch (CardException ex) {
- log.error("failed to verify pinspec: " + ex.getMessage(), ex);
+ log.error("failed to verify " + pinSpec.getLocalizedName() +
+ ": " + ex.getMessage(), ex);
throw new SignatureCardException(ex);
} finally {
try {
- icc.endExclusive();
+ getCard().endExclusive();
+ } catch (CardException ex) {
+ log.trace("failed to end exclusive card access: " + ex.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException {
+ try {
+ getCard().beginExclusive();
+
+ if (pinSpec.getContextAID() != null) {
+ selectFileAID(pinSpec.getContextAID());
+ }
+ char[] pin = pinProvider.providePIN(pinSpec, -1);
+ activatePIN(pinSpec.getKID(), pin);
+
+ } catch (CardException ex) {
+ log.error("Failed to activate " + pinSpec.getLocalizedName() +
+ ": " + ex.getMessage());
+ throw new SignatureCardException(ex.getMessage(), ex);
+ } finally {
+ try {
+ getCard().endExclusive();
} catch (CardException ex) {
log.trace("failed to end exclusive card access: " + ex.getMessage());
}
+ }
+ }
+
+ /**
+ * activates pin (newPIN) if not active
+ * @param pinSpec
+ * @param oldPIN
+ * @param newPIN
+ * @throws at.gv.egiz.smcc.LockedException
+ * @throws at.gv.egiz.smcc.VerificationFailedException
+ * @throws at.gv.egiz.smcc.NotActivatedException
+ * @throws at.gv.egiz.smcc.SignatureCardException
+ */
+ @Override
+ public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException {
+ try {
+ getCard().beginExclusive();
+
+ if (pinSpec.getContextAID() != null) {
+ selectFileAID(pinSpec.getContextAID());
+ }
+
+ int retries = verifyPIN(pinSpec.getKID());
+ do {
+ char[] newPin = pinProvider.providePIN(pinSpec, retries);
+ char[] oldPin = pinProvider.provideOldPIN(pinSpec, retries);
+ retries = changePIN(pinSpec.getKID(), oldPin, newPin);
+ } while (retries > 0);
+ //return on -1, 0 never reached: verifyPIN throws LockedEx
+ } catch (CardException ex) {
+ log.error("Failed to change " + pinSpec.getLocalizedName() +
+ ": " + ex.getMessage());
+ throw new SignatureCardException(ex.getMessage(), ex);
+ } finally {
+ try {
+ getCard().endExclusive();
+ } catch (CardException ex) {
+ log.trace("failed to end exclusive card access: " + ex.getMessage());
+ }
}
}
+
+ @Override
+ public void unblockPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws CancelledException, SignatureCardException, InterruptedException {
+ throw new SignatureCardException("Unblock not supported yet");
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // IFD related code
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * TODO implement VERIFY_PIN_START/FINISH (feature 0x01/0x02)
+ * @return
+ */
+ @Override
+ public boolean ifdSupportsFeature(byte feature) {
+ if (ifdCtrlCmds != null) {
+ return ifdCtrlCmds.containsKey(feature);
+ }
+ return false;
+ }
+
+ protected Map<Byte, Long> queryIFDFeatures() {
+
+ if (card_ == null) {
+ throw new NullPointerException("Need connected smart card to query IFD features");
+ }
+
+ Map<Byte, Long> ifdFeatures = new HashMap<Byte, Long>();
+
+ try {
+ if (log.isTraceEnabled()) {
+ log.trace("GET_FEATURE_REQUEST CtrlCode " + Integer.toHexString(getCtrlCode(GET_FEATURE_REQUEST)));
+ }
+ byte[] resp = card_.transmitControlCommand(getCtrlCode(GET_FEATURE_REQUEST), new byte[]{});
+
+ if (log.isTraceEnabled()) {
+ log.trace("GET_FEATURE_REQUEST Response " + SMCCHelper.toString(resp));
+ }
+
+ for (int i = 0; i + 5 < resp.length; i += 6) {
+ Byte feature = new Byte(resp[i]);
+ Long ctrlCode = new Long(
+ ((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 feature " + Integer.toHexString(feature.byteValue()) +
+ ": " + Long.toHexString(ctrlCode.longValue()));
+ }
+ ifdFeatures.put(feature, ctrlCode);
+ }
+
+ } catch (CardException ex) {
+ log.debug("Failed to query IFD features: " + ex.getMessage());
+ log.trace(ex);
+ log.info("IFD does not support PINPad");
+ return null;
+ }
+ return ifdFeatures;
+ }
+
+
+ protected byte ifdGetKeyPressed() throws CardException {
+ if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+
+ Long controlCode = (Long) ifdCtrlCmds.get(new Byte((byte) 0x05));
+
+ byte key = 0x00;
+ while (key == 0x00) {
+
+ byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
+
+ if (resp != null && resp.length > 0) {
+ key = resp[0];
+ }
+ }
+
+ System.out.println("Key: " + key);
+
+ }
+
+ return 0x00;
+ }
+
+ protected byte[] ifdVerifyPINFinish() throws CardException {
+ if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+
+ Long controlCode = (Long) ifdCtrlCmds.get(new Byte((byte) 0x02));
+
+ byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
+
+ System.out.println("CommandResp: " + toString(resp));
+
+ return resp;
+
+ }
+
+ return null;
+ }
+
+
+ /**
+ * assumes ifdSupportsVerifyPIN() == true
+ * @param pinVerifyStructure
+ * @return
+ * @throws javax.smartcardio.CardException
+ */
+// protected byte[] ifdVerifyPIN(byte[] pinVerifyStructure) throws CardException {
+//
+//// Long ctrlCode = (Long) ifdFeatures.get(FEATURE_IFD_PIN_PROPERTIES);
+//// if (ctrlCode != null) {
+//// if (log.isTraceEnabled()) {
+//// log.trace("PIN_PROPERTIES CtrlCode " + Integer.toHexString(ctrlCode.intValue()));
+//// }
+//// byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), new byte[] {});
+////
+//// if (log.isTraceEnabled()) {
+//// log.trace("PIN_PROPERTIES Response " + SMCCHelper.toString(resp));
+//// }
+//// }
+//
+//
+// Long ctrlCode = (Long) ifdFeatures.get(FEATURE_VERIFY_PIN_DIRECT);
+// if (ctrlCode == null) {
+// throw new NullPointerException("no CtrlCode for FEATURE_VERIFY_PIN_DIRECT");
+// }
+//
+// if (log.isTraceEnabled()) {
+// log.trace("VERIFY_PIN_DIRECT CtrlCode " + Integer.toHexString(ctrlCode.intValue()) +
+// ", PIN_VERIFY_STRUCTURE " + SMCCHelper.toString(pinVerifyStructure));
+// }
+// byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), pinVerifyStructure);
+//
+// if (log.isTraceEnabled()) {
+// log.trace("VERIFY_PIN_DIRECT Response " + SMCCHelper.toString(resp));
+// }
+// return resp;
+// }
+
+// protected Long getControlCode(Byte feature) {
+// if (ifdFeatures != null) {
+// return ifdFeatures.get(feature);
+// }
+// return null;
+// }
+
+ protected byte[] transmitControlCommand(Long ctrlCode, byte[] ctrlCommand)
+ throws CardException {
+// Long ctrlCode = (Long) ifdFeatures.get(feature);
+ if (ctrlCode == null) {
+ throw new NullPointerException("ControlCode " +
+ Integer.toHexString(ctrlCode.intValue()) + " not supported");
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("CtrlCommand (" + Integer.toHexString(ctrlCode.intValue()) +
+ ") " + SMCCHelper.toString(ctrlCommand));
+ }
+ byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), ctrlCommand);
+
+ if (log.isTraceEnabled()) {
+ log.trace("CtrlCommand Response " + SMCCHelper.toString(resp));
+ }
+ return resp;
+ }
+
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
new file mode 100644
index 00000000..d0622aa4
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.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;
+
+import at.gv.egiz.smcc.*;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+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/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
index e0104618..8fa80dcb 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
@@ -28,8 +28,30 @@
//
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 <clemens.orthacker@iaik.tugraz.at>
+ */
public interface PINProvider {
-
- public String providePIN(PINSpec spec, int retries) throws InterruptedException;
+
+ /**
+ *
+ * @param spec
+ * @param retries num of remaining retries or -1 if unknown
+ * (a positive value does <em>not</em> 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/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
index 3c5f38a2..91245c50 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
@@ -30,7 +30,6 @@ package at.gv.egiz.smcc;
import at.gv.egiz.smcc.util.SMCCHelper;
import java.util.Arrays;
-import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
@@ -223,15 +222,12 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
//new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
int retries = -1;
- String pin = null;
+ char[] pin = null;
boolean pinRequiered = false;
do {
if (pinRequiered) {
pin = provider.providePIN(spec, retries);
- if (pin == null) {
- throw new CancelledException();
- }
}
try {
getCard().beginExclusive();
@@ -240,7 +236,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
throw new NotActivatedException();
} catch (SecurityStatusNotSatisfiedException e) {
pinRequiered = true;
- retries = verifyPIN(null, KID_PIN_CARD);
+ retries = verifyPIN(KID_PIN_CARD);
} catch (VerificationFailedException e) {
pinRequiered = true;
retries = e.getRetries();
@@ -316,20 +312,17 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
//new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));
int retries = -1;
- String pin = null;
+ char[] pin = null;
do {
try {
getCard().beginExclusive();
selectFileAID(AID_DF_SS);
- retries = verifyPIN(null, KID_PIN_SS);
+ retries = verifyPIN(KID_PIN_SS); //, null);
} finally {
getCard().endExclusive();
}
pin = provider.providePIN(spec, retries);
- if (pin == null) {
- throw new CancelledException();
- }
try {
getCard().beginExclusive();
return createSignature(hash, AID_DF_SS, pin, KID_PIN_SS, DST_SS);
@@ -349,15 +342,12 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
//new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
int retries = -1;
- String pin = null;
+ char[] pin = null;
boolean pinRequiered = false;
do {
if (pinRequiered) {
pin = provider.providePIN(spec, retries);
- if (pin == null) {
- throw new CancelledException();
- }
}
try {
getCard().beginExclusive();
@@ -366,7 +356,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
throw new NotActivatedException();
} catch (SecurityStatusNotSatisfiedException e) {
pinRequiered = true;
- retries = verifyPIN(null, KID_PIN_CARD);
+ retries = verifyPIN(KID_PIN_CARD);
} catch (VerificationFailedException e) {
pinRequiered = true;
retries = e.getRetries();
@@ -389,13 +379,18 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
+
+ ////////////////////////////////////////////////////////////////////////
+ // PROTECTED METHODS (assume exclusive card access)
+ ////////////////////////////////////////////////////////////////////////
+
protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02,
0x04, fid, 256));
}
- private byte[] createSignature(byte[] hash, byte[] aid, String pin, byte kid,
+ private byte[] createSignature(byte[] hash, byte[] aid, char[] pin, byte kid,
byte[] dst) throws CardException, SignatureCardException {
// SELECT MF
@@ -403,7 +398,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
// SELECT DF
selectFileAID(aid);
// VERIFY
- int retries = verifyPIN(pin, kid);
+ int retries = verifyPIN(kid, pin);
if (retries != -1) {
throw new VerificationFailedException(retries);
}
@@ -417,7 +412,6 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
-
private void selectMF() throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,
@@ -467,58 +461,85 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
}
- /**
- * VERIFY PIN
- * <p>
- * If <code>pin</code> is <code>null</code> only the PIN status is checked and
- * returned.
- * </p>
- *
- * @param pin
- * the PIN (may be <code>null</code>)
- * @param kid
- * the KID of the PIN to be verified
- *
- * @return -1 if VERIFY PIN was successful, or the number of possible retries
- *
- * @throws LockedException
- * if the pin is locked
- * @throws NotActivatedException
- * if the card application has not been activated
- * @throws SignatureCardException
- * if VERIFY PIN fails for some other reason (card communication error)
- */
@Override
- public int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException {
+ protected int verifyPIN(byte kid, char[] pin)
+ throws LockedException, NotActivatedException, SignatureCardException {
try {
- CardChannel channel = getCardChannel();
-
- ResponseAPDU resp;
- if (pin == null) {
- resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid));
+ byte[] sw;
+ if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+ log.debug("verify PIN on IFD");
+ sw = transmitControlCommand(
+ ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT),
+ getPINVerifyStructure(kid));
+// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
} else {
- // BCD encode PIN and marshal PIN block
byte[] pinBlock = encodePINBlock(pin);
- resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false);
+ CardChannel channel = getCardChannel();
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false);
+ sw = new byte[2];
+ sw[0] = (byte) resp.getSW1();
+ sw[1] = (byte) resp.getSW2();
+ }
+ if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
+ return -1;
+ } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
+ throw new LockedException("[63:c0]");
+ } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
+ return sw[1] & 0x0f;
+ } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
+ //Authentisierungsmethode gesperrt
+ throw new LockedException("[69:83]");
+ } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
+ //referenzierte Daten sind reversibel gesperrt (invalidated)
+ throw new NotActivatedException("[69:84]");
+ } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
+ //Benutzungsbedingungen nicht erfüllt
+ throw new NotActivatedException("[69:85]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
+ throw new TimeoutException("[64:00]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
+ throw new CancelledException("[64:01]");
}
+ log.error("Failed to verify pin: SW="
+ + SMCCHelper.toString(sw));
+ throw new SignatureCardException(SMCCHelper.toString(sw));
+
+ } catch (CardException ex) {
+ log.error("smart card communication failed: " + ex.getMessage());
+ throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
+ }
+ }
- if (resp.getSW() == 0x63c0) {
- throw new LockedException("PIN locked.");
- } else if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) {
- // return number of possible retries
+ @Override
+ protected int verifyPIN(byte kid)
+ throws LockedException, NotActivatedException, SignatureCardException {
+ try {
+ CardChannel channel = getCardChannel();
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0x20, 0x00, kid), false);
+
+ if (resp.getSW() == 0x9000) {
+ return -1;
+ } else if (resp.getSW() == 0x63c0) {
+ throw new LockedException("[63:c0]");
+ } else if (resp.getSW1() == 0x63 && (resp.getSW2() & 0xf0) >> 4 == 0xc) {
return resp.getSW2() & 0x0f;
} else if (resp.getSW() == 0x6983) {
- throw new LockedException();
+ //Authentisierungsmethode gesperrt
+ throw new LockedException("[69:83]");
} else if (resp.getSW() == 0x6984) {
- // PIN LCS = "Initialized" (-> not activated)
- throw new NotActivatedException();
- } else if (resp.getSW() == 0x9000) {
- return -1; // success
- } else {
- throw new SignatureCardException("Failed to verify pin: SW="
- + Integer.toHexString(resp.getSW()));
+ //referenzierte Daten sind reversibel gesperrt (invalidated)
+ throw new NotActivatedException("[69:84]");
+ } else if (resp.getSW() == 0x6985) {
+ //Benutzungsbedingungen nicht erfüllt
+ throw new NotActivatedException("[69:85]");
}
+ log.error("Failed to verify pin: SW="
+ + Integer.toHexString(resp.getSW()));
+ throw new SignatureCardException("[" + Integer.toHexString(resp.getSW()) + "]");
+
} catch (CardException ex) {
log.error("smart card communication failed: " + ex.getMessage());
throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
@@ -526,24 +547,95 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
@Override
- public void reset() throws SignatureCardException {
+ protected int changePIN(byte kid, char[] oldPin, char[] newPin)
+ throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
try {
- super.reset();
- log.debug("select MF (e-card workaround)");
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, 0x0C));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("Failed to select MF after RESET: SW=" + Integer.toHexString(resp.getSW()) + ".");
+ byte[] sw;
+ if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+ log.debug("modify PIN on IFD");
+ sw = transmitControlCommand(
+ ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT),
+ getPINModifyStructure(kid));
+// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
+ } else {
+ byte[] cmd = new byte[16];
+ System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8);
+ System.arraycopy(encodePINBlock(newPin), 0, cmd, 8, 8);
+
+ CardChannel channel = getCardChannel();
+
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0x24, 0x00, kid, cmd), false);
+
+ sw = new byte[2];
+ sw[0] = (byte) resp.getSW1();
+ sw[1] = (byte) resp.getSW2();
+ }
+
+ // activates pin (newPIN) if not active
+ if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
+ return -1;
+ } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
+ throw new LockedException("[63:c0]");
+ } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
+ return sw[1] & 0x0f;
+ } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
+ //Authentisierungsmethode gesperrt
+ throw new LockedException("[69:83]");
+// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
+// //referenzierte Daten sind reversibel gesperrt (invalidated)
+// throw new NotActivatedException("[69:84]");
+// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
+// //Benutzungsbedingungen nicht erfüllt
+// throw new NotActivatedException("[69:85]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
+ throw new TimeoutException("[64:00]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
+ throw new CancelledException("[64:01]");
}
+ log.error("Failed to change pin: SW="
+ + SMCCHelper.toString(sw));
+ throw new SignatureCardException(SMCCHelper.toString(sw));
} catch (CardException ex) {
- log.error("Failed to select MF after RESET: " + ex.getMessage(), ex);
- throw new SignatureCardException("Failed to select MF after RESET");
+ log.error("smart card communication failed: " + ex.getMessage());
+ throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
}
}
+ @Override
+ protected void activatePIN(byte kid, char[] pin)
+ throws CancelledException, TimeoutException, SignatureCardException {
+ try {
+ CardChannel channel = getCardChannel();
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0x24, 0x01, kid, encodePINBlock(pin)), false);
+
+ log.trace("activate pin returned SW=" + Integer.toHexString(resp.getSW()));
- public String toString() {
- return "e-card";
+ if (resp.getSW1() == 0x9000) {
+ return;
+ } else if (resp.getSW() == 0x6983) {
+ //Authentisierungsmethode gesperrt
+ throw new LockedException("[69:83]");
+ } else if (resp.getSW() == 0x6984) {
+ //referenzierte Daten sind reversibel gesperrt (invalidated)
+ throw new NotActivatedException("[69:84]");
+ } else if (resp.getSW() == 0x6985) {
+ //Benutzungsbedingungen nicht erfüllt
+ throw new NotActivatedException("[69:85]");
+ } else if (resp.getSW() == 0x6400) {
+ throw new TimeoutException("[64:00]");
+ } else if (resp.getSW() == 0x6401) {
+ throw new CancelledException("[64:01]");
+ }
+ log.error("Failed to activate pin: SW=" +
+ Integer.toHexString(resp.getSW()));
+ throw new SignatureCardException("[" + Integer.toHexString(resp.getSW()) + "]");
+
+ } catch (CardException ex) {
+ log.error("smart card communication failed: " + ex.getMessage());
+ throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
+ }
}
/**
@@ -552,17 +644,20 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
* @return a 8 byte pin block consisting of length byte (0x2X),
* the BCD encoded pin and a 0xFF padding
*/
- private byte[] encodePINBlock(String pin) {
- char[] pinChars = pin.toCharArray();
- int numDigits = pinChars.length;
+ @Override
+ protected byte[] encodePINBlock(char[] pin) throws SignatureCardException {
+ if (pin == null || pin.length > 12) {
+ throw new SignatureCardException("invalid pin: " + pin);
+ }
+ int numDigits = pin.length;
int numBytes = (int) Math.ceil(numDigits/2.0);
byte[] pinBlock = new byte[8];
pinBlock[0] = (byte) (0x20 | numDigits);
for (int i = 0; i < numBytes; i++) {
- int p1 = 16*Character.digit(pinChars[i*2], 16);
- int p2 = (i*2+1 < numDigits) ? Character.digit(pinChars[i*2+1], 16) : 0xf;
+ int p1 = 16*Character.digit(pin[i*2], 16);
+ int p2 = (i*2+1 < numDigits) ? Character.digit(pin[i*2+1], 16) : 0xf;
pinBlock[i+1] = (byte) (p1 + p2);
}
Arrays.fill(pinBlock, numBytes + 1, pinBlock.length, (byte) 0xff);
@@ -570,111 +665,151 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
return pinBlock;
}
+
+ private byte[] getPINVerifyStructure(byte kid) {
+
+ byte bTimeOut = (byte) 00; // Default time out
+ byte bTimeOut2 = (byte) 00; // Default time out
+ byte bmFormatString = (byte) 0x89; // 1 0001 0 01
+ // ^------------ System unit = byte
+ // ^^^^------- PIN position in the frame = 1 byte
+ // ^----- PIN justification left
+ // ^^-- BCD format
+ byte bmPINBlockString = (byte) 0x47; // 0100 0111
+ // ^^^^--------- PIN length size: 4 bits
+ // ^^^^---- Length PIN = 7 bytes
+ byte bmPINLengthFormat = (byte) 0x04; // 000 0 0100
+ // ^-------- System bit units is bit
+ // ^^^^--- PIN length is at the 4th position bit
+ byte wPINMaxExtraDigitL = (byte) 0x04; // Max=4 digits
+ byte wPINMaxExtraDigitH = (byte) 0x04; // Min=4 digits
+ byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
+ byte bNumberMessage = (byte) 0x00; // No message
+ byte wLangIdL = (byte) 0x0C; // - English?
+ byte wLangIdH = (byte) 0x04; // \
+ byte bMsgIndex = (byte) 0x00; // Default Msg
+
+ byte[] apdu = new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08, // CLA INS P1 P2 LC
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff // ...
+ };
+
+ int offset = 0;
+ byte[] pinVerifyStructure = new byte[offset + 19 + apdu.length];
+ pinVerifyStructure[offset++] = bTimeOut;
+ pinVerifyStructure[offset++] = bTimeOut2;
+ pinVerifyStructure[offset++] = bmFormatString;
+ pinVerifyStructure[offset++] = bmPINBlockString;
+ pinVerifyStructure[offset++] = bmPINLengthFormat;
+ pinVerifyStructure[offset++] = wPINMaxExtraDigitL;
+ pinVerifyStructure[offset++] = wPINMaxExtraDigitH;
+ pinVerifyStructure[offset++] = bEntryValidationCondition;
+ pinVerifyStructure[offset++] = bNumberMessage;
+ pinVerifyStructure[offset++] = wLangIdL;
+ pinVerifyStructure[offset++] = wLangIdH;
+ pinVerifyStructure[offset++] = bMsgIndex;
+
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+
+ pinVerifyStructure[offset++] = (byte) apdu.length;
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+ pinVerifyStructure[offset++] = 0x00;
+ System.arraycopy(apdu, 0, pinVerifyStructure, offset, apdu.length);
- @Override
- public void activatePIN(PINSpec pinSpec, String pin)
- throws SignatureCardException {
- Card icc = getCard();
- try {
- icc.beginExclusive();
- CardChannel channel = icc.getBasicChannel();
-
- if (pinSpec.getContextAID() != null) {
- ResponseAPDU responseAPDU = transmit(channel,
- new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID()));
- if (responseAPDU.getSW() != 0x9000) {
- icc.endExclusive();
- String msg = "Select AID " + SMCCHelper.toString(pinSpec.getContextAID()) +
- ": SW=" + Integer.toHexString(responseAPDU.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
- }
- }
-
- ResponseAPDU responseAPDU = transmit(channel,
- new CommandAPDU(0x00, 0x24, 0x01, pinSpec.getKID(), encodePINBlock(pin)),
- false);
-
- icc.endExclusive();
-
- log.debug("activate pin returned SW=" + Integer.toHexString(responseAPDU.getSW()));
+ return pinVerifyStructure;
+ }
- if (responseAPDU.getSW() != 0x9000) {
- String msg = "Failed to activate " + pinSpec.getLocalizedName() +
- ": SW=" + Integer.toHexString(responseAPDU.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
- }
- } catch (CardException ex) {
- log.error("Failed to activate " + pinSpec.getLocalizedName() +
- ": " + ex.getMessage());
- throw new SignatureCardException(ex.getMessage(), ex);
- }
+ private byte[] getPINModifyStructure(byte kid) {
+
+ byte bTimeOut = (byte) 00; // Default time out
+ byte bTimeOut2 = (byte) 00; // Default time out
+ byte bmFormatString = (byte) 0x89; // 1 0001 0 01
+ // ^------------ System unit = byte
+ // ^^^^------- PIN position in the frame = 1 byte
+ // ^----- PIN justification left
+ // ^^-- BCD format
+ byte bmPINBlockString = (byte) 0x47; // 0100 0111
+ // ^^^^--------- PIN length size: 4 bits
+ // ^^^^---- Length PIN = 7 bytes
+ byte bmPINLengthFormat = (byte) 0x04; // 000 0 0100
+ // ^-------- System bit units is bit
+ // ^^^^--- PIN length is at the 4th position bit
+ byte bInsertionOffsetOld = (byte) 0x01; // insertion position offset in bytes
+ byte bInsertionOffsetNew = (byte) 0x08; // insertion position offset in bytes
+ byte wPINMaxExtraDigitL = (byte) 0x04; // Min=4 digits
+ byte wPINMaxExtraDigitH = (byte) 0x04; // Max=12 digits
+ byte bConfirmPIN = (byte) 0x00; // ??? need for confirm pin
+ byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
+ byte bNumberMessage = (byte) 0x00; // No message
+ byte wLangIdL = (byte) 0x0C; // - English?
+ byte wLangIdH = (byte) 0x04; // \
+ byte bMsgIndex1 = (byte) 0x00; // Default Msg
+ byte bMsgIndex2 = (byte) 0x00; // Default Msg
+ byte bMsgIndex3 = (byte) 0x00; // Default Msg
+
+ byte[] apdu = new byte[] {
+ (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10, // CLA INS P1 P2 LC
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // ...
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff // ...
+ };
+
+ int offset = 0;
+ byte[] pinModifyStructure = new byte[offset + 24 + apdu.length];
+ pinModifyStructure[offset++] = bTimeOut;
+ pinModifyStructure[offset++] = bTimeOut2;
+ pinModifyStructure[offset++] = bmFormatString;
+ pinModifyStructure[offset++] = bmPINBlockString;
+ pinModifyStructure[offset++] = bmPINLengthFormat;
+ pinModifyStructure[offset++] = bInsertionOffsetOld;
+ pinModifyStructure[offset++] = bInsertionOffsetNew;
+ pinModifyStructure[offset++] = wPINMaxExtraDigitL;
+ pinModifyStructure[offset++] = wPINMaxExtraDigitH;
+ pinModifyStructure[offset++] = bConfirmPIN;
+ pinModifyStructure[offset++] = bEntryValidationCondition;
+ pinModifyStructure[offset++] = bNumberMessage;
+ pinModifyStructure[offset++] = wLangIdL;
+ pinModifyStructure[offset++] = wLangIdH;
+ pinModifyStructure[offset++] = bMsgIndex1;
+ pinModifyStructure[offset++] = bMsgIndex2;
+ pinModifyStructure[offset++] = bMsgIndex3;
+
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+
+ pinModifyStructure[offset++] = (byte) apdu.length;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ System.arraycopy(apdu, 0, pinModifyStructure, offset, apdu.length);
+
+// log.debug("PIN MODIFY " + SMCCHelper.toString(pinModifyStructure));
+ return pinModifyStructure;
}
- /**
- * activates pin (newPIN) if not active
- * @param pinSpec
- * @param oldPIN
- * @param newPIN
- * @throws at.gv.egiz.smcc.LockedException
- * @throws at.gv.egiz.smcc.VerificationFailedException
- * @throws at.gv.egiz.smcc.NotActivatedException
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
@Override
- public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN)
- throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException {
- Card icc = getCard();
+ public void reset() throws SignatureCardException {
try {
- icc.beginExclusive();
- CardChannel channel = icc.getBasicChannel();
-
- if (pinSpec.getContextAID() != null) {
- ResponseAPDU responseAPDU = transmit(channel,
- new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID()));
- if (responseAPDU.getSW() != 0x9000) {
- icc.endExclusive();
- String msg = "Select AID " + SMCCHelper.toString(pinSpec.getContextAID()) +
- ": SW=" + Integer.toHexString(responseAPDU.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
- }
- }
-
- byte[] cmd = new byte[16];
- System.arraycopy(encodePINBlock(oldPIN), 0, cmd, 0, 8);
- System.arraycopy(encodePINBlock(newPIN), 0, cmd, 8, 8);
-
- ResponseAPDU responseAPDU = transmit(channel,
- new CommandAPDU(0x00, 0x24, 0x00, pinSpec.getKID(), cmd), false);
-
- icc.endExclusive();
-
- log.debug("change pin returned SW=" + Integer.toHexString(responseAPDU.getSW()));
-
- // activates pin (newPIN) if not active
- if (responseAPDU.getSW() == 0x63c0) {
- log.error(pinSpec.getLocalizedName() + " locked");
- throw new LockedException();
- } else if (responseAPDU.getSW1() == 0x63 && responseAPDU.getSW2() >> 4 == 0xc) {
- int retries = responseAPDU.getSW2() & 0x0f;
- log.error("wrong " + pinSpec.getLocalizedName() + ", " + retries + " retries");
- throw new VerificationFailedException(retries);
- } else if (responseAPDU.getSW() == 0x6983) {
- log.error(pinSpec.getLocalizedName() + " locked");
- throw new LockedException();
- } else if (responseAPDU.getSW() != 0x9000) {
- String msg = "Failed to change " + pinSpec.getLocalizedName() +
- ": SW=" + Integer.toHexString(responseAPDU.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
+ super.reset();
+ log.debug("select MF (e-card workaround)");
+ CardChannel channel = getCardChannel();
+ ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, 0x0C));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("Failed to select MF after RESET: SW=" + Integer.toHexString(resp.getSW()) + ".");
}
} catch (CardException ex) {
- log.error("Failed to change " + pinSpec.getLocalizedName() +
- ": " + ex.getMessage());
- throw new SignatureCardException(ex.getMessage(), ex);
+ log.error("Failed to select MF after RESET: " + ex.getMessage(), ex);
+ throw new SignatureCardException("Failed to select MF after RESET");
}
}
+ public String toString() {
+ return "e-card";
+ }
}
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 d7763be0..293b9c71 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
@@ -77,11 +77,11 @@ public class SWCard implements SignatureCard {
private KeyStore certifiedKeyStore;
- private String certifiedKeyStorePassword;
+ private char[] certifiedKeyStorePassword;
private KeyStore secureKeyStore;
- private String secureKeyStorePassword;
+ private char[] secureKeyStorePassword;
private Certificate certifiedCertificate;
@@ -195,7 +195,7 @@ public class SWCard implements SignatureCard {
}
- private String loadKeyStorePassword(String passwordFileName) throws SignatureCardException {
+ private char[] loadKeyStorePassword(String passwordFileName) throws SignatureCardException {
String fileName = getFileName(passwordFileName);
FileInputStream keyStorePasswordFile;
@@ -212,7 +212,7 @@ public class SWCard implements SignatureCard {
for (int l; (l = reader.read(b)) != -1;) {
sb.append(b, 0, l);
}
- return sb.toString();
+ return sb.toString().toCharArray();
} catch (IOException e) {
throw new SignatureCardException("Failed to read file '" + passwordFileName + "'.");
}
@@ -237,7 +237,7 @@ public class SWCard implements SignatureCard {
}
- private String getPassword(KeyboxName keyboxName) throws SignatureCardException {
+ private char[] getPassword(KeyboxName keyboxName) throws SignatureCardException {
if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
if (certifiedKeyStorePassword == null) {
@@ -311,7 +311,7 @@ public class SWCard implements SignatureCard {
public byte[] createSignature(byte[] hash, KeyboxName keyboxName, PINProvider provider) throws SignatureCardException, InterruptedException {
// KeyStore password
- String password = getPassword(keyboxName);
+ char[] password = getPassword(keyboxName);
if (password == null) {
@@ -325,7 +325,7 @@ public class SWCard implements SignatureCard {
}
- KeyStore keyStore = getKeyStore(keyboxName, password.toCharArray());
+ KeyStore keyStore = getKeyStore(keyboxName, password);
PrivateKey privateKey = null;
@@ -338,7 +338,7 @@ public class SWCard implements SignatureCard {
Key key = null;
while (key == null) {
try {
- key = keyStore.getKey(alias, password.toCharArray());
+ key = keyStore.getKey(alias, password);
} catch (UnrecoverableKeyException e) {
log.info("Failed to get Key from KeyStore. Wrong password?", e);
}
@@ -399,15 +399,27 @@ public class SWCard implements SignatureCard {
}
@Override
- public int verifyPIN(PINSpec pinSpec, String pin) throws LockedException, NotActivatedException, SignatureCardException {
- return -1;
+ public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws LockedException, NotActivatedException, SignatureCardException {
}
@Override
- public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN) throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException {
+ public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) throws SignatureCardException {
+ throw new UnsupportedOperationException("Not supported yet.");
}
@Override
- public void activatePIN(PINSpec pinSpec, String pin) throws SignatureCardException {
+ public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider) throws CancelledException, SignatureCardException, InterruptedException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public boolean ifdSupportsFeature(byte feature) {
+ return false;
}
}
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 3c2273b9..2097e6d3 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
@@ -36,6 +36,14 @@ import javax.smartcardio.CardTerminal;
public interface SignatureCard {
+ /**
+ * IFD FEATURES
+ */
+ static final Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 0x06);
+ static final Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 0x07);
+ static final Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 0x08);
+ static final Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 0x0a);
+
public static class KeyboxName {
public static KeyboxName SECURE_SIGNATURE_KEYPAIR = new KeyboxName(
@@ -123,29 +131,29 @@ public interface SignatureCard {
*/
public List<PINSpec> getPINSpecs();
- /**
- *
- * @param pinSpec descriptor which pin to verify
- * @param pin may be null to test the PIN status
- * @return the number of remaining retries or -1
- * @throws at.gv.egiz.smcc.LockedException
- * @throws at.gv.egiz.smcc.NotActivatedException
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
- public int verifyPIN(PINSpec pinSpec, String pin)
- throws LockedException, NotActivatedException, SignatureCardException;
+ public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException;
- public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN)
- throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException;
+ public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException;
- public void activatePIN(PINSpec pinSpec, String pin)
- throws SignatureCardException;
+ public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws CancelledException, SignatureCardException, InterruptedException;
+
+ public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
+ throws CancelledException, SignatureCardException, InterruptedException;
+
+ /**
+ * TODO
+ * @return
+ */
+ public boolean ifdSupportsFeature(byte feature);
/**
* Sets the local for evtl. required callbacks (e.g. PINSpec)
* @param locale must not be null;
*/
public void setLocale(Locale locale);
-
-
+
+
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java
index ab66e9a1..5146c275 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java
@@ -196,7 +196,7 @@ public class SignatureCardFactory {
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
},
"at.gv.egiz.smcc.ACOSCard"));
-
+
}
/**
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java b/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java
new file mode 100644
index 00000000..d14a4c15
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.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;
+
+public class TimeoutException extends SignatureCardException {
+
+ private static final long serialVersionUID = 1L;
+
+ public TimeoutException() {
+ super();
+ }
+
+ public TimeoutException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TimeoutException(String message) {
+ super(message);
+ }
+
+ public TimeoutException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/smcc/src/test/resources/log4j.properties b/smcc/src/test/resources/log4j.properties
index 94662fd2..053eac17 100644
--- a/smcc/src/test/resources/log4j.properties
+++ b/smcc/src/test/resources/log4j.properties
@@ -1,5 +1,5 @@
# loglever DEBUG, appender STDOUT
-log4j.rootLogger=DEBUG, STDOUT
+log4j.rootLogger=TRACE, STDOUT
#log4j.logger.at.gv.egiz.slbinding.RedirectEventFilter=DEBUG, STDOUT
# STDOUT appender