diff options
Diffstat (limited to 'smcc/src/main/java')
5 files changed, 172 insertions, 32 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 86223854..57925240 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -28,6 +28,7 @@ // package at.gv.egiz.smcc; +import at.gv.egiz.smcc.util.SMCCHelper; import java.nio.charset.Charset; import javax.smartcardio.CardChannel; @@ -104,9 +105,12 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { public ACOSCard() { super("at/gv/egiz/smcc/ACOSCard"); - pinSpecs.add(PINSPEC_INF, new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"), KID_PIN_INF, null)); - pinSpecs.add(PINSPEC_DEC, new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name"), KID_PIN_DEC, null)); - pinSpecs.add(PINSPEC_SIG, new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"), KID_PIN_SIG, null)); + pinSpecs.add(PINSPEC_INF, + new PINSpec(0, 8, "[0-9]", getResourceBundle().getString("inf.pin.name"), KID_PIN_INF, AID_DEC)); + pinSpecs.add(PINSPEC_DEC, + new PINSpec(0, 8, "[0-9]", getResourceBundle().getString("dec.pin.name"), KID_PIN_DEC, AID_DEC)); + pinSpecs.add(PINSPEC_SIG, + new PINSpec(0, 8, "[0-9]", getResourceBundle().getString("sig.pin.name"), KID_PIN_SIG, AID_SIG)); } /* (non-Javadoc) @@ -334,14 +338,13 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { CardChannel channel = getCardChannel(); - byte[] asciiPIN = pin.getBytes(Charset.forName("ASCII")); - byte[] encodedPIN = new byte[8]; - System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length, - encodedPIN.length)); - ResponseAPDU resp; try { - resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, encodedPIN), false); + if (pin != null) { + resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, encodePINBlock(pin)), false); + } else { + 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); @@ -419,7 +422,28 @@ 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 + */ + @Override + public 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 + public void activatePIN(byte kid, byte[] contextAID, String pin) throws SignatureCardException { + throw new SignatureCardException("PIN activation not supported by this card"); + } } 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 cb068725..63301bd1 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -28,14 +28,13 @@ // package at.gv.egiz.smcc; +import at.gv.egiz.smcc.util.SMCCHelper; 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 javax.smartcardio.ATR; @@ -443,4 +442,54 @@ public abstract class AbstractSignatureCard implements SignatureCard { public List<PINSpec> getPINSpecs() { return pinSpecs; } + + public void changePIN(byte kid, byte[] contextAID, String oldPIN, String newPIN) throws SignatureCardException, VerificationFailedException { + Card icc = getCard(); + try { + icc.beginExclusive(); + CardChannel channel = icc.getBasicChannel(); + + if (contextAID != null) { + ResponseAPDU responseAPDU = transmit(channel, + new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, contextAID)); + if (responseAPDU.getSW() != 0x9000) { + icc.endExclusive(); + String msg = "Failed to change PIN " + SMCCHelper.toString(new byte[]{kid}) + + ": Failed to select AID " + SMCCHelper.toString(contextAID) + + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + 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, kid, cmd), false); + + icc.endExclusive(); + + if (responseAPDU.getSW1() == 0x63 && responseAPDU.getSW2() >> 4 == 0xc) { + int retries = responseAPDU.getSW2() & 0x0f; + log.error("Failed VERIFY PIN, " + retries + " tries left"); + throw new VerificationFailedException(retries); + } + if (responseAPDU.getSW() != 0x9000) { + String msg = "Failed to change PIN " + + SMCCHelper.toString(new byte[]{kid}) + ": " + + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + + } catch (CardException ex) { + log.error("Failed to change PIN: " + ex.getMessage()); + throw new SignatureCardException(ex.getMessage(), ex); + } + } + + abstract byte[] encodePINBlock(String pin); + } 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 ae43629e..b1288f74 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -28,9 +28,9 @@ // package at.gv.egiz.smcc; -import java.math.BigInteger; +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; @@ -162,8 +162,14 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard */ public STARCOSCard() { super("at/gv/egiz/smcc/STARCOSCard"); - pinSpecs.add(PINSPEC_CARD, new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"), KID_PIN_CARD, null)); - pinSpecs.add(PINSPEC_SS, new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"), KID_PIN_SS, AID_DF_SS)); + pinSpecs.add(PINSPEC_CARD, + new PINSpec(4, 12, "[0-9]", + getResourceBundle().getString("card.pin.name"), + KID_PIN_CARD, null)); + pinSpecs.add(PINSPEC_SS, + new PINSpec(6, 12, "[0-9]", + getResourceBundle().getString("sig.pin.name"), + KID_PIN_SS, AID_DF_SS)); } @Override @@ -491,21 +497,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard if (pin == null) { resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid)); } else { - // PIN length in bytes - int len = (int) Math.ceil(pin.length() / 2); - // BCD encode PIN and marshal PIN block - byte[] pinBytes = new BigInteger(pin, 16).toByteArray(); - byte[] pinBlock = new byte[8]; - if (len < pinBytes.length) { - System.arraycopy(pinBytes, pinBytes.length - len, pinBlock, 1, len); - } else { - System.arraycopy(pinBytes, 0, pinBlock, len - pinBytes.length + 1, - pinBytes.length); - } - pinBlock[0] = (byte) (0x20 + len * 2); - Arrays.fill(pinBlock, len + 1, 8, (byte) 0xff); - + byte[] pinBlock = encodePINBlock(pin); resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false); } @@ -553,6 +546,65 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard return "e-card"; } - + /** + * BCD encodes the pin, pads with 0xFF and prepends the pins length + * @param pin + * @return a 8 byte pin block consisting of length byte (0x2X), + * the BCD encoded pin and a 0xFF padding + */ + @Override + public byte[] encodePINBlock(String pin) { + char[] pinChars = pin.toCharArray(); + int numDigits = pinChars.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; + pinBlock[i+1] = (byte) (p1 + p2); + } + Arrays.fill(pinBlock, numBytes + 1, pinBlock.length, (byte) 0xff); +// log.trace("BCD encoded PIN block: " + SMCCHelper.toString(pinBlock)); + + return pinBlock; + } + + public void activatePIN(byte kid, byte[] contextAID, String pin) throws SignatureCardException { + Card icc = getCard(); + try { + icc.beginExclusive(); + CardChannel channel = icc.getBasicChannel(); + + if (contextAID != null) { + ResponseAPDU responseAPDU = transmit(channel, + new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, contextAID)); + if (responseAPDU.getSW() != 0x9000) { + icc.endExclusive(); + String msg = "Failed to activate PIN " + SMCCHelper.toString(new byte[]{kid}) + + ": Failed to select AID " + SMCCHelper.toString(contextAID) + + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + } + + ResponseAPDU responseAPDU = transmit(channel, + new CommandAPDU(0x00, 0x24, 0x01, kid, encodePINBlock(pin)), false); + + icc.endExclusive(); + + if (responseAPDU.getSW() != 0x9000) { + String msg = "Failed to activate PIN " + SMCCHelper.toString(new byte[]{kid}) + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + } catch (CardException ex) { + log.error("Failed to activate PIN: " + ex.getMessage()); + throw new SignatureCardException(ex.getMessage(), ex); + } + } } 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 8dc4ac2a..57aeb994 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -403,4 +403,12 @@ public class SWCard implements SignatureCard { return new ArrayList<PINSpec>(); } + @Override + public void changePIN(byte kid, byte[] contextAID, String oldPIN, String newPIN) throws SignatureCardException, VerificationFailedException { + } + + @Override + public void activatePIN(byte kid, byte[] contextAID, String pin) throws SignatureCardException { + } + } 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 1e5e09c8..a88593bc 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java @@ -31,7 +31,6 @@ package at.gv.egiz.smcc; import java.util.List; import java.util.Locale; -import java.util.Map; import javax.smartcardio.Card; import javax.smartcardio.CardTerminal; @@ -135,11 +134,19 @@ public interface SignatureCard { */ public int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException; + public void changePIN(byte kid, byte[] contextAID, + String oldPIN, String newPIN) + throws SignatureCardException, VerificationFailedException; + + public void activatePIN(byte kid, byte[] contextAID, + String pin) + throws SignatureCardException; + /** * Sets the local for evtl. required callbacks (e.g. PINSpec) * @param locale must not be null; */ public void setLocale(Locale locale); - + } |