/** * Used to get the name of the readers connected. * * @return A list of the names. */ public ArrayList<String> getReadersName() { ArrayList<String> list = new ArrayList<>(); try { for (CardTerminal terminal : terminalFactory.terminals().list()) list.add(terminal.getName()); } catch (CardException exception) { } return list; }
private synchronized boolean activateTerminal() { Interfacer.getLogger().log("ACTIVATE TERMINAL"); // select which terminal to use if (_cardTerminal != null) _activeCardTerminal = _cardTerminal; else { while (_activeCardTerminal == null) { try { for (CardTerminal cardTerminalLoop : _cardTerminals) { if (cardTerminalLoop.isCardPresent() && !cardTerminalLoop.getName().toUpperCase().contains("EMULATOR")) { _activeCardTerminal = cardTerminalLoop; break; } } if (_activeCardTerminal == null) { Interfacer.getLogger().log("INSERT CARD (s)"); Thread.sleep(1000); } } catch (Exception e) { } } } Interfacer.getLogger().log("ACTIVE TERMINAL: " + _activeCardTerminal.getName()); try { // wait for a card to be put in the terminal while (!_activeCardTerminal.isCardPresent() && !_activeCardTerminal.getName().toUpperCase().contains("EMULATOR")) { Interfacer.getLogger().log("INSERT CARD (s)"); Thread.sleep(1000); } if (_activePassportService == null) { _activeCardService = new TerminalCardService(_activeCardTerminal); _activePassportService = new PassportService(_activeCardService); _activePassportService.open(); } Interfacer.getLogger().log("CARD INSERTED AT: " + _activeCardTerminal.getName()); return true; } catch (Exception e) { e.printStackTrace(); } // something went wrong if we reached this point, clear the selected terminal Interfacer.getLogger().log("NO TERMINAL COULD BE ACTIVATED"); return false; }
/** * What is doing the thread. * * <p>Will check if there is a reader available containing the wanted name (will call {@link * TerminalListener#cardReaderRemoved()} ()} if a listener is removed or added). If it is the case * it will wait for a card placed, call {@link TerminalListener#cardAdded(RFIDCard)}, wait for the * card to be removed then call {@link TerminalListener#cardRemoved()} */ @Override public void run() { while (!Thread.interrupted()) { if (terminalFactory == null) try { Thread.sleep(500); } catch (InterruptedException e) { } boolean lastPresent = this.isPresent; try { final CardTerminals terminalList = terminalFactory.terminals(); CardTerminal cardTerminal = null; try { for (CardTerminal terminal : terminalList.list()) if (terminal.getName().equals(this.terminalName)) { cardTerminal = terminal; this.isPresent = true; break; } } catch (CardException exception) { } if (cardTerminal == null) this.isPresent = false; if (this.isPresent != lastPresent) { if (this.isPresent) logger.log(Level.INFO, "Starting listening terminal " + cardTerminal.getName()); else logger.log(Level.INFO, "Stopped listening"); for (TerminalListener listener : this.listenersTerminal) if (this.isPresent) listener.cardReaderAdded(); else listener.cardReaderRemoved(); } if (!this.isPresent) continue; logger.log(Level.INFO, "Waiting for card..."); cardTerminal.waitForCardPresent(0); logger.log(Level.INFO, "Card detected"); this.lastCard = getCardInfos(cardTerminal.connect("*")); for (TerminalListener listener : this.listenersTerminal) listener.cardAdded(this.lastCard); cardTerminal.waitForCardAbsent(0); this.lastCard = null; logger.log(Level.INFO, "Card removed"); for (TerminalListener listener : this.listenersTerminal) listener.cardRemoved(); } catch (Exception exception) { logger.log(Level.WARNING, "", exception); } } }
public CardSession createCardSession(String rdr) { CardTerminal term = null; synchronized (terms) { for (CardTerminal t : terms) { if (t.getName().equals(rdr)) term = t; } } return new CardSessionImpl(term, rdr); }
@Override public List<TerminalState> start() throws SCIOException { logger.trace("Entering start()."); if (pendingEvents != null) { throw new IllegalStateException( "Trying to initialize already initialized watcher instance."); } pendingEvents = new LinkedList<>(); terminals = new HashSet<>(); cardPresent = new HashSet<>(); try { // call wait for change and directly afterwards get current list of cards // with a bit of luck no change has happened in between and the list is coherent own.terminals.waitForChange(1); List<CardTerminal> javaTerminals = own.terminals.list(); ArrayList<TerminalState> result = new ArrayList<>(javaTerminals.size()); // fill sets according to state of the terminals logger.debug("Detecting initial terminal status."); for (CardTerminal next : javaTerminals) { String name = next.getName(); boolean cardInserted = next.isCardPresent(); logger.debug("Terminal='{}' cardPresent={}", name, cardInserted); terminals.add(name); if (cardInserted) { cardPresent.add(name); result.add(new TerminalState(name, true)); } else { result.add(new TerminalState(name, false)); } } // return list of our terminals logger.trace("Leaving start() with {} states.", result.size()); return Collections.unmodifiableList(result); } catch (CardException ex) { if (getCode(ex) == SCIOErrorCode.SCARD_E_NO_READERS_AVAILABLE) { logger.debug("No reader available exception."); return Collections.emptyList(); } else if (getCode(ex) == SCIOErrorCode.SCARD_E_NO_SERVICE) { logger.debug("No service available exception, reloading PCSC and returning empty list."); parent.reloadFactory(); own.loadTerminals(); return Collections.emptyList(); } String msg = "Failed to retrieve status from the PCSC system."; logger.error(msg, ex); throw new SCIOException(msg, getCode(ex), ex); } catch (IllegalStateException ex) { logger.debug("No reader available exception."); return Collections.emptyList(); } }
public String toString() { StringBuffer result = new StringBuffer(); List<CardTerminal> terminals = manager.getTerminals(); for (CardTerminal terminal : terminals) { result.append("[" + (manager.isPolling(terminal) ? "X" : " ") + "] "); result.append(terminal.getName()); result.append("\n"); } result.append("\n"); result.append("Service = " + service); result.append("\n"); return result.toString(); }
/** * Create a new instance of PassportLink. All CardTerminals will be listed. Upon a request all * terminals will be checked for the presence of a passport. The first terminal to respond will be * chosen for as long as the passport is present. */ public PassportLink() { Security.insertProviderAt(PROVIDER, 4); _cardManager = CardManager.getInstance(); _cardTerminals = _cardManager.getTerminals(); _activeCardTerminal = null; _cardTerminal = null; _activeCardService = null; _activePassportService = null; Vector<CardTerminal> terminalsToRemove = new Vector<CardTerminal>(); for (CardTerminal cardTerminalLoop : _cardTerminals) { if (cardTerminalLoop.getName().toUpperCase().contains("EMULATOR")) { Interfacer.getLogger().log("Removing emulator terminal."); terminalsToRemove.add(cardTerminalLoop); } Interfacer.getLogger().log("terminal name: " + cardTerminalLoop.getName()); } for (CardTerminal removeTerminal : terminalsToRemove) _cardManager.getTerminals().remove(removeTerminal); }
/** * openChannel * * @param applet * @return Channel * @throws Exception */ private CardChannel openChannel(AppletModel applet) throws Exception { if (channel != null) { try { channel.close(); } catch (Exception e) { // } channel = null; } if (card != null) { try { card.disconnect(true); } catch (Exception e) { // } card = null; } TerminalFactory factory = TerminalFactory.getDefault(); CardTerminals cardterminals = factory.terminals(); try { List<CardTerminal> terminals = cardterminals.list(); System.out.println("Terminals: " + terminals); for (CardTerminal terminal : terminals) { terminal.waitForCardPresent(1000); if (terminal.isCardPresent()) { System.out.println(terminal.getName() + ": Card present!"); card = terminal.connect("*"); channel = card.getBasicChannel(); return channel; } } throw new WolfException(MSG_READER_TIME_OUT); } catch (Exception e) { throw e; } }
private static void work(CardTerminal reader, OptionSet args) throws CardException { if (!reader.isCardPresent()) { System.out.println("No card in " + reader.getName()); return; } FileOutputStream o = null; if (args.has(OPT_DUMP)) { try { o = new FileOutputStream((File) args.valueOf(OPT_DUMP)); } catch (FileNotFoundException e) { System.err.println("Can not dump to " + args.valueOf(OPT_DUMP)); } } reader = LoggingCardTerminal.getInstance(reader, o); // This allows to override the protocol for RemoteTerminal as well. final String protocol; if (args.has(OPT_T0)) { protocol = "T=0"; } else if (args.has(OPT_T1)) { protocol = "T=1"; } else { protocol = "*"; } if (args.has(CMD_APDU)) { Card c = null; try { c = reader.connect(protocol); if (args.has(CMD_APDU)) { for (Object s : args.valuesOf(CMD_APDU)) { CommandAPDU a = new CommandAPDU(HexUtils.stringToBin((String) s)); ResponseAPDU r = c.getBasicChannel().transmit(a); if (args.has(OPT_ERROR) && r.getSW() != 0x9000) { System.out.println( "Card returned " + String.format("%04X", r.getSW()) + ", exiting!"); return; } } } } catch (CardException e) { if (TerminalManager.getExceptionMessage(e) != null) { System.out.println("PC/SC failure: " + TerminalManager.getExceptionMessage(e)); } else { throw e; } } finally { if (c != null) { c.disconnect(true); } } } else if (args.has(OPT_CONNECT)) { String remote = (String) args.valueOf(OPT_CONNECT); JSONMessagePipe transport = null; try { if (remote.startsWith("http://") || remote.startsWith("https://")) { if (args.has(OPT_PINNED)) { transport = HTTPTransport.open( new URL(remote), certFromPEM(((File) args.valueOf(OPT_PINNED)).getPath())); } else { transport = HTTPTransport.open(new URL(remote), null); } } else { transport = SocketTransport.connect(string2socket(remote), null); } // Connect the transport and the terminal CmdlineRemoteTerminal c = new CmdlineRemoteTerminal(transport, reader); c.forceProtocol(protocol); // Run c.run(); } catch (IOException e) { System.err.println("Communication error: " + e.getMessage()); } finally { if (transport != null) transport.close(); } } }
public static void main(String[] argv) throws Exception { OptionSet args = parseOptions(argv); if (args.has(OPT_VERBOSE)) { verbose = true; // Set up slf4j simple in a way that pleases us System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug"); System.setProperty("org.slf4j.simpleLogger.showThreadName", "true"); System.setProperty("org.slf4j.simpleLogger.showShortLogName", "true"); System.setProperty("org.slf4j.simpleLogger.levelInBrackets", "true"); } else { System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "warn"); } if (args.has(OPT_VERSION)) { String version = "apdu4j " + getVersion(SCTool.class); // Append host information version += "\nRunning on " + System.getProperty("os.name"); version += " " + System.getProperty("os.version"); version += " " + System.getProperty("os.arch"); version += ", Java " + System.getProperty("java.version"); version += " by " + System.getProperty("java.vendor"); System.out.println(version); } if (args.has(OPT_TEST_SERVER)) { // TODO: have the possibility to run SocketServer as well? RemoteTerminalServer srv = new RemoteTerminalServer(TestServer.class); srv.start(string2socket((String) args.valueOf(OPT_TEST_SERVER))); System.console().readLine("Press enter to stop\n"); srv.stop(1); System.exit(0); } // List TerminalFactory providers if (args.has(OPT_PROVIDERS)) { Provider providers[] = Security.getProviders("TerminalFactory.PC/SC"); if (providers != null) { System.out.println("Existing TerminalFactory providers:"); for (Provider p : providers) { System.out.println(p.getName()); } } } // Fix properties on non-windows platforms TerminalManager.fixPlatformPaths(); // Only applies to SunPCSC if (args.has(OPT_NO_GET_RESPONSE)) { System.setProperty("sun.security.smartcardio.t0GetResponse", "false"); System.setProperty("sun.security.smartcardio.t1GetResponse", "false"); } // Override PC/SC library path if (args.has(OPT_LIB)) { System.setProperty("sun.security.smartcardio.library", (String) args.valueOf(OPT_LIB)); } TerminalFactory tf = null; CardTerminals terminals = null; try { // Get a terminal factory if (args.has(OPT_PROVIDER)) { String pn = (String) args.valueOf(OPT_PROVIDER); String pt = (String) args.valueOf(OPT_PROVIDER_TYPE); tf = loadFactory(pn, pt); } else if (args.has(OPT_SUN)) { tf = loadFactory(SUN_CLASS, null); } else if (args.has(OPT_JNA)) { tf = loadFactory(JNA_CLASS, null); } else { tf = TerminalFactory.getDefault(); } if (verbose) { System.out.println( "# Using " + tf.getProvider().getClass().getCanonicalName() + " - " + tf.getProvider()); if (System.getProperty(TerminalManager.lib_prop) != null) { System.out.println( "# " + TerminalManager.lib_prop + "=" + System.getProperty(TerminalManager.lib_prop)); } } // Get all terminals terminals = tf.terminals(); } catch (Exception e) { // XXX: we catch generic Exception here to avoid importing JNA. // Try to get a meaningful message String msg = TerminalManager.getExceptionMessage(e); if (msg == null) msg = e.getMessage(); System.out.println("No readers: " + msg); System.exit(1); } // Terminals to work on List<CardTerminal> do_readers = new ArrayList<CardTerminal>(); try { // List Terminals if (args.has(CMD_LIST)) { List<CardTerminal> terms = terminals.list(); if (verbose) { System.out.println( "# Found " + terms.size() + " terminal" + (terms.size() == 1 ? "" : "s")); } if (terms.size() == 0) { System.err.println("No readers found"); System.exit(1); } for (CardTerminal t : terms) { String vmd = " "; try (PinPadTerminal pp = new PinPadTerminal(t)) { pp.probe(); // Verify, Modify, Display if (verbose) { vmd += "["; vmd += pp.canVerify() ? "V" : " "; vmd += pp.canModify() ? "M" : " "; vmd += pp.hasDisplay() ? "D" : " "; vmd += "] "; } } catch (CardException e) { if (verbose) { System.err.println("Could not probe PinPad: " + e.getMessage()); } } System.out.println((t.isCardPresent() ? "[*]" : "[ ]") + vmd + t.getName()); if (args.has(OPT_VERBOSE) && t.isCardPresent()) { Card c = t.connect("DIRECT"); String atr = HexUtils.encodeHexString(c.getATR().getBytes()).toUpperCase(); c.disconnect(false); System.out.println(" " + atr); if (args.has(OPT_WEB)) { String url = "http://smartcard-atr.appspot.com/parse?ATR=" + atr; if (Desktop.isDesktopSupported()) { Desktop.getDesktop().browse(new URI(url + "&from=apdu4j")); } else { System.out.println(" " + url); } } } } } // Select terminals to work on if (args.has(OPT_READER)) { String reader = (String) args.valueOf(OPT_READER); CardTerminal t = terminals.getTerminal(reader); if (t == null) { System.err.println("Reader \"" + reader + "\" not found."); System.exit(1); } do_readers = Arrays.asList(t); } else { do_readers = terminals.list(State.CARD_PRESENT); if (do_readers.size() > 1 && !args.hasArgument(OPT_ALL)) { System.err.println("More than one reader with a card found."); System.err.println("Run with --" + OPT_ALL + " to work with all found cards"); System.exit(1); } else if (do_readers.size() == 0 && !args.has(CMD_LIST)) { // But if there is a single reader, wait for a card insertion List<CardTerminal> empty = terminals.list(State.CARD_ABSENT); if (empty.size() == 1 && args.has(OPT_WAIT)) { CardTerminal rdr = empty.get(0); System.out.println("Please enter a card into " + rdr.getName()); if (!empty.get(0).waitForCardPresent(30000)) { System.out.println("Timeout."); } else { do_readers = Arrays.asList(rdr); } } else { System.err.println("No reader with a card found!"); System.exit(1); } } } } catch (CardException e) { System.out.println("Could not list readers: " + TerminalManager.getExceptionMessage(e)); e.printStackTrace(); } for (CardTerminal t : do_readers) { work(t, args); } }
/** * Create a new instance of PassportLink specifying the name of the CardTerminal to use. * * @param terminalToUse Name of CardTerminal to use. */ public PassportLink(String terminalToUse) { this(); for (CardTerminal cardTerminalLoop : _cardTerminals) { if (cardTerminalLoop.getName().equals(terminalToUse)) _cardTerminal = cardTerminalLoop; } }
/** * Wait for events in the system. The SmartcardIO wait function only reacts on card events, new * and removed terminals go unseen. in order to fix this, we wait only a short time and check * the terminal list periodically. * * @param timeout Timeout values as in {@link #waitForChange(long)}. * @return The first value is the changed flag . It is {@code true} if a change the terminals * happened, {@code false} if a timeout occurred. <br> * The second value is the error flag. It is {@code true} if an error was used to indicate * that no terminals are connected, {@code false} otherwise. * @throws CardException Thrown if any error related to the SmartcardIO occured. * @throws SCIOException Thrown if the thread was interrupted. Contains the code {@link * SCIOErrorCode#SCARD_E_SERVICE_STOPPED}. */ private Pair<Boolean, Boolean> internalWait(long timeout) throws CardException, SCIOException { // the SmartcardIO wait function only reacts on card events, new and removed terminals go // unseen // to fix this, we wait only a short time and check the terminal list periodically if (timeout < 0) { throw new IllegalArgumentException("Negative timeout value given."); } else if (timeout == 0) { timeout = Long.MAX_VALUE; } while (true) { if (timeout == 0) { // waited for all time and nothing happened return new Pair<>(false, false); } // calculate next wait slice long waitTime; if (timeout < WAIT_DELTA) { waitTime = timeout; timeout = 0; } else { timeout = timeout - WAIT_DELTA; waitTime = WAIT_DELTA; } try { // check if there is something new on the card side // due to the wait call blocking every other smartcard operation, we only wait for the // actual events // very shortly and sleep for the rest of the time boolean change = own.terminals.waitForChange(1); if (change) { return new Pair<>(true, false); } sleep(waitTime); // try again after sleeping change = own.terminals.waitForChange(1); if (change) { return new Pair<>(true, false); } } catch (CardException ex) { switch (getCode(ex)) { case SCARD_E_NO_SERVICE: logger.debug("No service available exception, reloading PCSC."); parent.reloadFactory(); own.loadTerminals(); case SCARD_E_NO_READERS_AVAILABLE: // send events that everything is removed if there are any terminals connected right // now if (!terminals.isEmpty()) { return new Pair<>(true, true); } else { logger.debug("Waiting for PCSC system to become available again."); // if nothing changed, wait a bit and try again sleep(waitTime); continue; } default: throw ex; } } catch (IllegalStateException ex) { // send events that everything is removed if there are any terminals connected right now if (!terminals.isEmpty()) { return new Pair<>(true, true); } else { logger.debug("Waiting for PCSC system to become available again."); // if nothing changed, wait a bit and try again sleep(waitTime); continue; } } // check if there is something new on the terminal side ArrayList<CardTerminal> currentTerms = new ArrayList<>(own.terminals.list()); if (currentTerms.size() != terminals.size()) { return new Pair<>(true, false); } // same size, but still compare terminal names HashSet<String> newTermNames = new HashSet<>(); for (CardTerminal next : currentTerms) { newTermNames.add(next.getName()); } int sizeBefore = newTermNames.size(); if (sizeBefore != terminals.size()) { return new Pair<>(false, false); } newTermNames.addAll(terminals); int sizeAfter = newTermNames.size(); if (sizeBefore != sizeAfter) { return new Pair<>(false, false); } } }
@Override public StateChangeEvent waitForChange(long timeout) throws SCIOException { logger.trace("Entering waitForChange()."); if (pendingEvents == null) { throw new IllegalStateException("Calling wait on uninitialized watcher instance."); } // try to return any present events first StateChangeEvent nextEvent = pendingEvents.poll(); if (nextEvent != null) { logger.trace("Leaving waitForChange() with queued event."); return nextEvent; } else { Pair<Boolean, Boolean> waitResult; try { waitResult = internalWait(timeout); } catch (CardException ex) { String msg = "Error while waiting for a state change in the terminals."; logger.error(msg, ex); throw new SCIOException(msg, getCode(ex), ex); } boolean changed = waitResult.p1; boolean error = waitResult.p2; if (!changed) { logger.trace("Leaving waitForChange() with no event."); return new StateChangeEvent(); } else { // something has changed, retrieve actual terminals from the system and see what has // changed Collection<String> newTerminals = new HashSet<>(); Collection<String> newCardPresent = new HashSet<>(); // only ask for terminals if there is no error if (!error) { try { List<CardTerminal> newStates = own.terminals.list(); for (CardTerminal next : newStates) { String name = next.getName(); newTerminals.add(name); if (next.isCardPresent()) { newCardPresent.add(name); } } } catch (CardException ex) { String msg = "Failed to retrieve status of the observed terminals."; logger.error(msg, ex); throw new SCIOException(msg, getCode(ex), ex); } } // calculate what has actually happened // removed cards Collection<String> cardRemoved = subtract(cardPresent, newCardPresent); Collection<StateChangeEvent> crEvents = createEvents(EventType.CARD_REMOVED, cardRemoved); // removed terminals Collection<String> termRemoved = subtract(terminals, newTerminals); Collection<StateChangeEvent> trEvents = createEvents(EventType.TERMINAL_REMOVED, termRemoved); // added terminals Collection<String> termAdded = subtract(newTerminals, terminals); Collection<StateChangeEvent> taEvents = createEvents(EventType.TERMINAL_ADDED, termAdded); // added cards Collection<String> cardAdded = subtract(newCardPresent, cardPresent); Collection<StateChangeEvent> caEvents = createEvents(EventType.CARD_INSERTED, cardAdded); // update internal status with the calculated state terminals = newTerminals; cardPresent = newCardPresent; pendingEvents.addAll(crEvents); pendingEvents.addAll(trEvents); pendingEvents.addAll(taEvents); pendingEvents.addAll(caEvents); // use remove so we get an exception when no event has been recorded // this would mean our algorithm is corrupt logger.trace("Leaving waitForChange() with fresh event."); return pendingEvents.remove(); } } }