From 2dbf2347bc78fd835c857ad438514fb6251f6f7a Mon Sep 17 00:00:00 2001 From: clemenso Date: Thu, 2 Apr 2009 19:13:48 +0000 Subject: 1.1-RC7 (pinpad revisited) git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@325 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../java/at/gv/egiz/smcc/ccid/DefaultReader.java | 345 ++++++++++++++++++--- 1 file changed, 305 insertions(+), 40 deletions(-) (limited to 'smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java') diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java index 2cc77dc9..9b1787a0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java @@ -20,6 +20,8 @@ import at.gv.egiz.smcc.*; import at.gv.egiz.smcc.util.SMCCHelper; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.smartcardio.Card; import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; @@ -35,12 +37,17 @@ public class DefaultReader implements CCID { protected final static Log log = LogFactory.getLog(DefaultReader.class); private static int CTL_CODE(int code) { - return 0x42000000 + 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); } int IOCTL_GET_FEATURE_REQUEST = CTL_CODE(3400); - protected Card icc; protected CardTerminal ct; @@ -58,14 +65,19 @@ public class DefaultReader implements CCID { features = queryFeatures(); } - public Card connect() throws CardException { //SignatureCardException { -// try { + /** + * + * @return the card terminals name + */ + @Override + public String getName() { + return ct.getName(); + } + + @Override + public Card connect() throws CardException { icc = ct.connect("*"); return icc; -// } catch (CardException ex) { -// log.error(ex.getMessage(), ex); -// throw new SignatureCardException("Failed to connect to card: " + ex.getMessage()); -// } } Map queryFeatures() { @@ -81,7 +93,7 @@ public class DefaultReader implements CCID { " on " + ct.getName()); } byte[] resp = icc.transmitControlCommand(IOCTL_GET_FEATURE_REQUEST, - new byte[]{}); + new byte[0]); if (log.isTraceEnabled()) { log.trace("Response TLV " + SMCCHelper.toString(resp)); @@ -91,8 +103,10 @@ public class DefaultReader implements CCID { // control code value for supported feature (in big endian) for (int i = 0; i < resp.length; i += 6) { Byte feature = new Byte(resp[i]); - int ioctlBigEndian = (resp[i + 2] << 24) | - (resp[i + 3] << 16) | (resp[i + 4] << 8) | resp[i + 5]; + int ioctlBigEndian = ((0xff & resp[i + 2]) << 24) | + ((0xff & resp[i + 3]) << 16) | + ((0xff & resp[i + 4]) << 8) | + (0xff & resp[i + 5]); Integer ioctl = new Integer(ioctlBigEndian); if (log.isInfoEnabled()) { log.info("CCID supports " + FEATURES[feature.intValue()] + @@ -117,37 +131,29 @@ public class DefaultReader implements CCID { return false; } -// public Integer getIOCTL(Byte feature) { -// if (features != null) { -// return features.get(feature); +// protected byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand) +// throws CardException { +// try { +// if (!features.containsKey(feature)) { +// throw new CardException(FEATURES[feature.intValue()] + " not supported"); +// } +// int ioctl = features.get(feature); +// if (log.isTraceEnabled()) { +// log.trace("CtrlCommand (" + Integer.toHexString(ioctl) + +// ") " + SMCCHelper.toString(ctrlCommand)); +// } +// byte[] resp = icc.transmitControlCommand(ioctl, ctrlCommand); +// if (log.isTraceEnabled()) { +// log.trace("CtrlCommand Response " + SMCCHelper.toString(resp)); +// } +// return resp; +// } catch (CardException ex) { +// log.error(ex.getMessage()); +// throw new SignatureCardException("Failed to transmit CtrlCommand for " + +// FEATURES[feature.intValue()]); // } -// return null; // } - @Override - public byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand) - throws SignatureCardException { - try { - if (!features.containsKey(feature)) { - throw new SignatureCardException(FEATURES[feature.intValue()] + " not supported"); - } - int ioctl = features.get(feature); - if (log.isTraceEnabled()) { - log.trace("CtrlCommand (" + Integer.toHexString(ioctl) + - ") " + SMCCHelper.toString(ctrlCommand)); - } - byte[] resp = icc.transmitControlCommand(ioctl, ctrlCommand); - if (log.isTraceEnabled()) { - log.trace("CtrlCommand Response " + SMCCHelper.toString(resp)); - } - return resp; - } catch (CardException ex) { - log.error(ex.getMessage()); - throw new SignatureCardException("Failed to transmit CtrlCommand for " + - FEATURES[feature.intValue()]); - } - } - @Override public byte getbTimeOut() { @@ -162,7 +168,7 @@ public class DefaultReader implements CCID { @Override public byte getwPINMaxExtraDigitL() { - return (byte) 0x12; + return (byte) 0x12; // signed int } @Override @@ -175,6 +181,265 @@ public class DefaultReader implements CCID { return (byte) 0x02; // validation key pressed } + void verifyPinStart(byte[] PIN_VERIFY) throws CardException { + if (!features.containsKey(FEATURE_VERIFY_PIN_START)) { + throw new CardException("FEATURE_VERIFY_PIN_START not supported"); + } + 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)); + } + } + } + + byte[] verifyPinFinish() throws CardException { + if (!features.containsKey(FEATURE_VERIFY_PIN_FINISH)) { + throw new CardException("FEATURE_VERIFY_FINISH_FINISH not supported"); + } + 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)); + } + + void modifyPinStart(byte[] PIN_MODIFY) throws CardException { + if (!features.containsKey(FEATURE_MODIFY_PIN_START)) { + throw new CardException("FEATURE_MODIFY_PIN_START not supported"); + } + 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)); + } + } + } + + byte[] modifyPinFinish() throws CardException { + if (!features.containsKey(FEATURE_MODIFY_PIN_FINISH)) { + throw new CardException("FEATURE_MODIFY_FINISH_FINISH not supported"); + } + 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)); + } + + + byte getKeyPressed() throws CardException { + if (!features.containsKey(FEATURE_GET_KEY_PRESSED)) { + throw new CardException("FEATURE_GET_KEY_PRESSED not supported"); + } + int ioctl = features.get(FEATURE_GET_KEY_PRESSED); +// if (log.isTraceEnabled()) { +// log.trace("GET_KEY_PRESSED (" + Integer.toHexString(ioctl) + ")"); +// } + 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)); + } + + + + @Override + public byte[] verifyPinDirect(byte[] PIN_VERIFY) throws CardException { + if (!features.containsKey(FEATURE_VERIFY_PIN_DIRECT)) { + throw new CardException("FEATURE_VERIFY_PIN_DIRECT not supported"); + } + 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; + } + + @Override + public byte[] verifyPin(byte[] PIN_VERIFY) throws PINOperationAbortedException, CardException { + verifyPinStart(PIN_VERIFY); + byte resp; + do { + resp = getKeyPressed(); + if (resp == (byte) 0x00) { + synchronized(this) { + try { + wait(200); + } catch (InterruptedException ex) { + log.error("interrupted in VERIFY_PIN"); + } + } + } else if (resp == (byte) 0x0d) { + log.trace("user confirmed"); + break; + } else if (resp == (byte) 0x2b) { + log.trace("user entered valid key (0-9)"); + } else if (resp == (byte) 0x1b) { + log.info("user cancelled VERIFY_PIN via cancel button"); + return verifyPinFinish(); +// return new byte[] { (byte) 0x64, (byte) 0x01 }; + } else if (resp == (byte) 0x08) { + log.trace("user pressed correction/backspace button"); + } else if (resp == (byte) 0x0e) { + log.trace("timeout occured"); + return verifyPinFinish(); // return 0x64 0x00 + } else if (resp == (byte) 0x40) { + log.trace("PIN_Operation_Aborted"); + throw new PINOperationAbortedException("PIN_Operation_Aborted"); + } else if (resp == (byte) 0x0a) { + log.trace("all keys cleared"); + } 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); //resp != (byte) 0x0d); + + return verifyPinFinish(); + } + + @Override + public byte[] modifyPin(byte[] PIN_MODIFY) throws PINOperationAbortedException, CardException { + modifyPinStart(PIN_MODIFY); + log.debug(PIN_MODIFY[9] + " pin confirmations expected"); + + byte resp; + short pinConfirmations = 0; + do { + resp = getKeyPressed(); + if (resp == (byte) 0x00) { + synchronized(this) { + try { + wait(200); + } catch (InterruptedException ex) { + log.error("interrupted in MODIFY_PIN"); + } + } + } else if (resp == (byte) 0x0d) { + log.trace("user confirmed"); + pinConfirmations++; + continue; + } else if (resp == (byte) 0x2b) { + log.trace("user entered valid key (0-9)"); + } else if (resp == (byte) 0x1b) { + log.info("user cancelled MODIFY_PIN via cancel button"); +// return verifyPinFinish(); + return new byte[] { (byte) 0x64, (byte) 0x01 }; + } else if (resp == (byte) 0x08) { + log.trace("user pressed correction/backspace button"); + } else if (resp == (byte) 0x0e) { + log.trace("timeout occured"); + return new byte[] { (byte) 0x64, (byte) 0x00 }; +// return verifyPinFinish(); // return 0x64 0x00 + } else if (resp == (byte) 0x40) { + log.trace("PIN_Operation_Aborted"); + throw new PINOperationAbortedException("PIN_Operation_Aborted"); + } else if (resp == (byte) 0x0a) { + log.trace("all keys cleared"); + } 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 (pinConfirmations < PIN_MODIFY[9]); + + return modifyPinFinish(); + } + + /** + * NOT SUPPORTED FOR ACOS ON OMNIKEY CardMan 3621 + * + * @param PIN_MODIFY + * @return + * @throws javax.smartcardio.CardException + */ + @Override + public byte[] modifyPinDirect(byte[] PIN_MODIFY) throws CardException { + if (!features.containsKey(FEATURE_MODIFY_PIN_DIRECT)) { + throw new CardException("FEATURE_MODIFY_PIN_DIRECT not supported"); + } + 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; + } + + +//[TRACE] SmartCardIO - terminal 'PC/SC terminal OMNIKEY CardMan 3621 0' card inserted : PC/SC card in OMNIKEY CardMan 3621 0, protocol T=1, state OK +//[TRACE] DefaultReader - GET_FEATURE_REQUEST 313520 on OMNIKEY CardMan 3621 0 +//[TRACE] DefaultReader - Response TLV [01:04:00:31:30:00:02:04:00:31:2f:d4:03:04:00:31:30:04:04:04:00:31:2f:dc:05:04:00:31:2f:e0:0a:04 +//00:31:30:08] +//[INFO] DefaultReader - CCID supports FEATURE_VERIFY_PIN_START: 313000 +//[INFO] DefaultReader - CCID supports FEATURE_VERIFY_PIN_FINISH: ffffffd4 +//[INFO] DefaultReader - CCID supports FEATURE_MODIFY_PIN_START: 313004 +//[INFO] DefaultReader - CCID supports FEATURE_MODIFY_PIN_FINISH: ffffffdc +//[INFO] DefaultReader - CCID supports FEATURE_GET_KEY_PRESSED: ffffffe0 +//[INFO] DefaultReader - CCID supports FEATURE_IFD_PIN_PROPERTIES: 313008 +//[TRACE] AbstractSignatureCard - Setting IFS (information field size) to 254 + // protected byte ifdGetKeyPressed() throws CardException { // if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) { -- cgit v1.2.3