/* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.poreid.security.pcscforjava; import org.poreid.pcscforjava.ATR; import org.poreid.pcscforjava.CardChannel; import org.poreid.pcscforjava.CardPermission; import org.poreid.pcscforjava.PCSCErrorValues; import org.poreid.pcscforjava.CardException; import org.poreid.pcscforjava.Card; import static org.poreid.security.pcscforjava.PCSC.*; import static org.poreid.security.pcscforjava.PCSCDefines.*; /** * Card implementation. * * @since 1.6 * @author Andreas Sterbenz * @author Matthieu Leromain */ final class CardImpl extends Card { private static enum State { OK, REMOVED, DISCONNECTED }; // the terminal that created this card private final TerminalImpl terminal; // the native SCARDHANDLE final long cardId; // atr of this card private ATR atr; // protocol in use, one of SCARD_PROTOCOL_T0 and SCARD_PROTOCOL_T1 final int protocol; // sharing mode in use, one of SCARD_SHARE_SHARED and SCARD_SHARE_DIRECT and // SCARD_SHARE_EXCLUSIVE final int sharingMode; // the basic logical channel (channel 0) private final ChannelImpl basicChannel; // state of this card connection private volatile State state; /** * Constructs a new Card object. * * <p>This constructor is called by subclasses only. Application should * call the {@linkplain CardTerminal#connect CardTerminal.connect()} * method to obtain a {@link Card Card} object. * * @param terminal the terminal which contains the smart card object. * @param protocol the protocol string. It can be: <br /> * <ul> * <li>direct: for terminal direct access.</li> * <li>*: for shared access with T = 0 or T = 1 protocol.</li> * <li>t=0: for shared access with T = 0 protocol.</li> * <li>t=1: for shared access with T = 1 protocol.</li> * <li>exclusive_*: for exclusive access with T = 0 or T = 1 protocol.</li> * <li>exclusive_t=0: for exclusive access with T = 0 protocol.</li> * <li>exclusive_t=1: for exclusive access with T = 1 protocol.</li> * </ul> * @param iForceProtocol the protocol string. It can be: <br /> * <ul> * <li>SCARD_PROTOCOL_T0: for T = 0 protocol.</li> * <li>SCARD_PROTOCOL_T1: for T = 1 protocol.</li> * <li>SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1: for T = 0 or 1 protocol.</li> * </ul> * This is made for bug in some Mac OS X drivers which do not like the * SCARD_PROTOCOL_UNDEFINED value. * * @throw PCSCException if a PCSC exception occurs. */ CardImpl(TerminalImpl terminal, String protocol, int iForceProtocol) throws PCSCException { this.terminal = terminal; int _iSharingMode = SCARD_SHARE_SHARED; int connectProtocol; if(protocol.equalsIgnoreCase("direct")) { connectProtocol = iForceProtocol; _iSharingMode = SCARD_SHARE_DIRECT; } else { if(protocol.contains("*")) connectProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; else if(protocol.toLowerCase().contains("t=0")) connectProtocol = SCARD_PROTOCOL_T0; else if(protocol.toLowerCase().contains("t=1")) connectProtocol = SCARD_PROTOCOL_T1; else throw new IllegalArgumentException("Unsupported protocol " + protocol); if(protocol.toLowerCase().contains("exclusive_")) _iSharingMode = SCARD_SHARE_EXCLUSIVE; } cardId = SCardConnect(terminal.contextId, terminal.name, _iSharingMode, connectProtocol); if(_iSharingMode != SCARD_SHARE_DIRECT) { byte[] status = new byte[2]; byte[] atrBytes = SCardStatus(cardId, status); atr = new ATR(atrBytes, getFrequency()); // I do not know why but sometimes SCardStatus does not return // the correct ATR !! while((atrBytes[0] != 0x3B) && (atrBytes[0] != 0x3F)) { atrBytes = SCardStatus(cardId, status); atr = new ATR(atrBytes, getFrequency()); } this.protocol = status[1] & 0xff; } else { // Returns fake ATR byte[] atrBytes = new byte[17]; atrBytes[0] = 0x3B; atrBytes[1] = 0x0F; atrBytes[2] = 0x44; atrBytes[3] = 0x49; atrBytes[4] = 0x52; atrBytes[5] = 0x45; atrBytes[6] = 0x43; atrBytes[7] = 0x54; atrBytes[8] = 0x5F; atrBytes[9] = 0x41; atrBytes[10] = 0x54; atrBytes[11] = 0x52; atrBytes[12] = 0x5F; atrBytes[13] = 0x46; atrBytes[14] = 0x41; atrBytes[15] = 0x4B; atrBytes[16] = 0x45; // Default smart card clock is 4MHz atr = new ATR(atrBytes, 4000000); this.protocol = 0; } this.sharingMode = _iSharingMode; basicChannel = new ChannelImpl(this, 0); state = State.OK; } /** * Constructs a new Card object. * * <p>This constructor is called by subclasses only. Application should * call the {@linkplain CardTerminal#connect CardTerminal.connect()} * method to obtain a {@link Card Card} object. * * @param terminal the terminal which contains the smart card object. * @param protocol the protocol string. It can be: <br /> * <ul> * <li>direct: for terminal direct access.</li> * <li>*: for shared access with T = 0 or T = 1 protocol.</li> * <li>t=0: for shared access with T = 0 protocol.</li> * <li>t=1: for shared access with T = 1 protocol.</li> * <li>exclusive_*: for exclusive access with T = 0 or T = 1 protocol.</li> * <li>exclusive_t=0: for exclusive access with T = 0 protocol.</li> * <li>exclusive_t=1: for exclusive access with T = 1 protocol.</li> * </ul> * * @throw PCSCException if a PCSC exception occurs. */ CardImpl(TerminalImpl terminal, String protocol) throws PCSCException { this(terminal, protocol, SCARD_PROTOCOL_UNDEFINED); } /** * Check the state of the smart card. */ void checkState() { State s = state; if (s == State.DISCONNECTED) { throw new IllegalStateException("org.poreid.pcscforjava.CardImpl." + "checkState PCSCException: SCARD_W_UNPOWERED_CARD"); } else if (s == State.REMOVED) { throw new IllegalStateException("org.poreid.pcscforjava.CardImpl." + "checkState PCSCException: SCARD_W_REMOVED_CARD"); } } /** * Check if the smart card is valid or not. * @return */ @Override public boolean isValid() { if (state != State.OK) { return false; } // ping card via SCardStatus try { SCardStatus(cardId, new byte[2]); return true; } catch (PCSCException e) { // If the connection is performed in direct mode then no problem // with this card. if(this.getSharingMode() == SCARD_SHARE_DIRECT) return true; state = State.REMOVED; return false; } } /** * Check the security of the smart card. * @param action the action which must be secured. */ private void checkSecurity(String action) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new CardPermission(terminal.name, action)); } } /** * Manage the removal card from PCSC exception. * @param e the PCSC exception. */ void handleError(PCSCException e) { if (e.code == PCSCErrorValues.SCARD_W_REMOVED_CARD) { state = State.REMOVED; } } /** * Returns the {@link ATR ATR} of this card. * * @return the {@link ATR ATR} of this card. */ public ATR getATR() { return atr; } /** * Returns the protocol in use for this card. * * @return the protocol in use for this card, for example "T=0", "T=1", * "DIRECT". */ public String getProtocol() { switch (protocol) { case SCARD_PROTOCOL_T0: return "T=0"; case SCARD_PROTOCOL_T1: return "T=1"; default: // should never occur return "Unknown protocol " + protocol; } } /** * Returns the sharing mode of the smart card connection. * * @return the sharing mode of the smart card connection. * It can be:<br /><ul> * <li>{@link SCARD_SHARE_EXCLUSIVE SCARD_SHARE_EXCLUSIVE} for exclusive * mode.</li> * <li>{@link SCARD_SHARE_DIRECT SCARD_SHARE_DIRECT} for direct mode.</li> * <li>{@link SCARD_SHARE_SHARED SCARD_SHARE_SHARED} for share mode.</li> * </ul> */ public int getSharingMode() { return this.sharingMode; } /** * Returns the {@link CardChannel CardChannel} for the basic logical * channel. * <br />The basic logical channel has a channel number of 0. * * @return the {@link CardChannel CardChannel} for the basic logical * channel. * * @throws SecurityException if a SecurityManager exists and the * caller does not have the required. * {@linkplain CardPermission permission}. * @throws IllegalStateException if this card object has been disposed of * via the {@linkplain #disconnect disconnect()} method. */ public CardChannel getBasicChannel() { checkSecurity("getBasicChannel"); checkState(); return basicChannel; } /** * Gets the status word of a byte array. * @param b the byte array. * @return -1 if an error occurs.<br /> * The status word of the byte array. */ private static int getSW(byte[] b) { if (b.length < 2) { return -1; } int sw1 = b[b.length - 2] & 0xff; int sw2 = b[b.length - 1] & 0xff; return (sw1 << 8) | sw2; } /** * Command to open a channel. */ private static byte[] commandOpenChannel = new byte[] {0, 0x70, 0, 0, 1}; /** * Opens a new logical channel to the card and returns it. The channel is * opened by issuing a <code>MANAGE CHANNEL</code> command that should use * the format <code>[00 70 00 00 01]</code>. * * @return the new logical {@link CardChannel CardChannel}. * * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. * @throws CardException is a new logical channel could not be opened. * @throws IllegalStateException if this card object has been disposed of * via the {@linkplain #disconnect disconnect()} method. */ public CardChannel openLogicalChannel() throws CardException { checkSecurity("openLogicalChannel"); checkState(); checkExclusive(); try { byte[] response = SCardTransmit (cardId, protocol, commandOpenChannel, 0, commandOpenChannel.length); if ((response.length != 3) || (getSW(response) != 0x9000)) { throw new CardException ("org.poreid.pcscforjava.CardImpl.openLogicalChannel " + "PCSCException: SCARD_F_UNKNOWN_ERROR Card response: " + PCSC.toString(response)); } return new ChannelImpl(this, response[0]); } catch (PCSCException e) { handleError(e); throw new CardException("org.poreid.pcscforjava." + "CardImpl.openLogicalChannel " + "PCSCException: " + e.getMessage(), e); } } /** * Check the excusivity of the request. * @throws CardException if a card exception occurs. */ void checkExclusive() throws CardException { } /** * Requests exclusive access to this card. * * <p>Once a thread has invoked {@link beginExclusive beginExclusive}, only * this thread is allowed to communicate with this card until it calls * {@link endExclusive endExclusive}. Other threads attempting communication * will receive a {@link CardException CardException}. * * <p>Applications have to ensure that exclusive access is correctly * released. This can be achieved by executing * the {@link beginExclusive beginExclusive} and {@link endExclusive * endExclusive} calls in a <code>try ... finally</code> block. * * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. * @throws CardException if exclusive access has already been set * or if exclusive access could not be established. * @throws IllegalStateException if this card object has been disposed of * via the {@linkplain #disconnect disconnect()} method. */ public synchronized void beginExclusive() throws CardException { checkSecurity("exclusive"); checkState(); try { SCardBeginTransaction(cardId); } catch (PCSCException e) { handleError(e); throw new CardException("org.poreid.pcscforjava." + "CardImpl.beginExclusive " + "PCSCException: SCARD_F_UNKNOWN_ERROR", e); } } /** * Releases the exclusive access previously established using * {@link beginExclusive beginExclusive}. * * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. * @throws IllegalStateException if the active Thread does not currently * have exclusive access to this card or if this card object has been * disposed of via the {@linkplain #disconnect disconnect()} method. * @throws CardException if the operation failed. */ public synchronized void endExclusive() throws CardException { checkState(); try { SCardEndTransaction(cardId, SCARD_LEAVE_CARD); } catch (PCSCException e) { handleError(e); throw new CardException("org.poreid.pcscforjava." + "CardImpl.endExclusive " + "PCSCException: SCARD_F_UNKNOWN_ERROR", e); } } /** * Transmits a control command to the terminal device. * * <p>This can be used to, for example, control terminal functions like * a built-in PIN pad or biometrics. * * @param controlCode the control code of the command. * @param command the command data. * * @return the response of the {@link transmitControlCommand * transmitControlCommand}. * * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. * @throws NullPointerException if command is null. * @throws CardException if the card operation failed. * @throws IllegalStateException if this card object has been disposed of * via the {@linkplain #disconnect disconnect()} method. */ @Override public byte[] transmitControlCommand(int controlCode, byte[] command) throws CardException { checkSecurity("transmitControl"); checkState(); checkExclusive(); if (command == null) { throw new NullPointerException(); } try { byte[] r = SCardControl(cardId, controlCode, command); if(r == null) return new byte[0]; return r; } catch (PCSCException e) { handleError(e); throw new CardException("org.poreid.pcscforjava." + "CardImpl.transmitControlCommand " + "PCSCException: " + e.getMessage(), e); } } /** * Disconnects the connection with this card. After this method returns, * calling methods on this object or in {@link CardChannel CardChannels} * associated with this object that require interaction with the card will * raise an IllegalStateException. * * @param iDisposition must be {@link SCARD_LEAVE_CARD SCARD_LEAVE_CARD} to * leave the card in its current state or {@link SCARD_RESET_CARD * SCARD_RESET_CARD} to reset the card before the disconnection or * {@link SCARD_UNPOWER_CARD SCARD_UNPOWER_CARD} to power off the card * before the disconnection or {@link SCARD_EJECT_CARD SCARD_EJECT_CARD} to * eject the card before the disconnection. * * @throws CardException if the card operation failed. * @throws IllegalArgumentException if a parameter is incoherent with this * function. * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. */ @Override public void disconnect(int iDisposition) throws CardException { checkSecurity("disconnect"); if (state != State.OK) return; switch(iDisposition) { case SCARD_LEAVE_CARD: case SCARD_RESET_CARD: case SCARD_UNPOWER_CARD: case SCARD_EJECT_CARD: break; default: throw new IllegalArgumentException("Unsupported disposition " + iDisposition); } checkExclusive(); try { if(iDisposition != SCARD_LEAVE_CARD) SCardDisconnect(cardId, iDisposition); } catch (PCSCException e) { throw new CardException("org.poreid.pcscforjava." + "CardImpl.disconnect " + "PCSCException: " + e.getMessage(), e); } finally { if(iDisposition != SCARD_LEAVE_CARD) { state = State.DISCONNECTED; this.terminal.notifyDisconnection(); } } } /** * Gets an attribute of this card. * * @param iAttribute is the identifier for the attribute to get and must be: * <br /><br /><ul> * <li>{@link SCARD_ATTR_ATR_STRING SCARD_ATTR_ATR_STRING}: Answer to reset * (ATR) string.</li> *<li>{@link SCARD_ATTR_CHANNEL_ID SCARD_ATTR_CHANNEL_ID}: * unsigned long encoded as 0xDDDDCCCC, where DDDD = data channel type * and CCCC = channel number:<br /> * The following encodings are defined for DDDD:<br /><ul> * <li>0x01 serial I/O; CCCC is a port number.</li> * <li>0x02 parallel I/O; CCCC is a port number.</li> * <li>0x04 PS/2 keyboard port; CCCC is zero.</li> * <li>0x08 SCSI; CCCC is SCSI ID number.</li> * <li>0x10 IDE; CCCC is device number.</li> * <li>0x20 USB; CCCC is device number.</li> * <li>0xFy vendor-defined interface with y in the range zero through 15; * CCCC is vendor defined.</li></ul> *<li>{@link SCARD_ATTR_CHARACTERISTICS SCARD_ATTR_CHARACTERISTICS}: * unsigned long indicating which mechanical characteristics are supported. * <br />If zero, no special characteristics are supported.<br /> * Note that multiple bits can be set:<br /><ul> * <li>0x00000001 Card swallowing mechanism.</li> * <li>0x00000002 Card ejection mechanism.</li> * <li>0x00000004 Card capture mechanism.</li> * <li>All other values are reserved for future use (RFU).</li></ul> *<li>{@link SCARD_ATTR_CURRENT_BWT SCARD_ATTR_CURRENT_BWT}: Current block * waiting time. *<li>{@link SCARD_ATTR_CURRENT_CLK SCARD_ATTR_CURRENT_CLK}: Current clock * rate, in kHz. *<li>{@link SCARD_ATTR_CURRENT_CWT SCARD_ATTR_CURRENT_CWT}: Current * character waiting time. *<li>{@link SCARD_ATTR_CURRENT_D SCARD_ATTR_CURRENT_D}: Bit rate conversion * factor. *<li>{@link SCARD_ATTR_CURRENT_EBC_ENCODING * SCARD_ATTR_CURRENT_EBC_ENCODING}: * Current error block control encoding.<br /><ul> * <li>0 = Longitudinal Redundancy Check (LRC).</li> * <li>1 = Cyclical Redundancy Check (CRC).</li></ul> *<li>{@link SCARD_ATTR_CURRENT_F SCARD_ATTR_CURRENT_F}: Clock conversion * factor. *<li>{@link SCARD_ATTR_CURRENT_IFSC SCARD_ATTR_CURRENT_IFSC}: Current byte * size for information field size card. *<li>{@link SCARD_ATTR_CURRENT_IFSD SCARD_ATTR_CURRENT_IFSD}: Current byte * size for information field size device. *<li>{@link SCARD_ATTR_CURRENT_N SCARD_ATTR_CURRENT_N}: Current guard time. *<li>{@link SCARD_ATTR_CURRENT_PROTOCOL_TYPE * SCARD_ATTR_CURRENT_PROTOCOL_TYPE}: * unsigned long encoded as 0x0rrrpppp where rrr is RFU and should be * 0x000.<br /> * pppp encodes the current protocol type. Whichever bit has been set * indicates which ISO protocol is currently in use. (For example, if bit * zero is set, T=0 protocol is in effect.) *<li>{@link SCARD_ATTR_CURRENT_W SCARD_ATTR_CURRENT_W}: Current work * waiting time. *<li>{@link SCARD_ATTR_DEFAULT_CLK SCARD_ATTR_DEFAULT_CLK}: Default clock * rate, in kHz. * <li>{@link SCARD_ATTR_DEFAULT_DATA_RATE SCARD_ATTR_DEFAULT_DATA_RATE}: * Default data rate, in bps. *<li>{@link SCARD_ATTR_DEVICE_FRIENDLY_NAME * SCARD_ATTR_DEVICE_FRIENDLY_NAME}: Reader's display name. *<li>{@link SCARD_ATTR_DEVICE_IN_USE SCARD_ATTR_DEVICE_IN_USE}: Reserved * for future use. *<li>{@link SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME}: * Reader's system name. *<li>{@link SCARD_ATTR_DEVICE_UNIT SCARD_ATTR_DEVICE_UNIT}: * Instance of this vendor's reader attached to the computer. The first * instance will be device unit 0, the next will be unit 1 (if it is the * same brand of reader) and so on.<br /> * Two different brands of readers will both have zero for this value. *<li>{@link SCARD_ATTR_ICC_INTERFACE_STATUS * SCARD_ATTR_ICC_INTERFACE_STATUS}: Single byte. Zero if smart card * electrical contact is not active; nonzero if contact is active. *<li>{@link SCARD_ATTR_ICC_PRESENCE SCARD_ATTR_ICC_PRESENCE}: * Single byte indicating smart card presence:<br /><ul> * <li>0 = not present.</li> * <li>1 = card present but not swallowed (applies only if reader supports * smart card swallowing).</li> * <li>2 = card present (and swallowed if reader supports smart card * swallowing).</li> * <li>4 = card confiscated.</li></ul> *<li>{@link SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_ICC_TYPE_PER_ATR}: * Single byte indicating smart card type:<br /><ul> * <li>0 = unknown type.</li> * <li>1 = 7816 Asynchronous.</li> * <li>2 = 7816 Synchronous.</li> * <li>Other values RFU.</li></ul> *<li>{@link SCARD_ATTR_MAX_CLK SCARD_ATTR_MAX_CLK}: Maximum clock rate, in * kHz. *<li>{@link SCARD_ATTR_MAX_DATA_RATE SCARD_ATTR_MAX_DATA_RATE}: Maximum * data rate, in bps. *<li>{@link SCARD_ATTR_MAX_IFSD SCARD_ATTR_MAX_IFSD}: Maximum bytes for * information file size device. *<li>{@link SCARD_ATTR_POWER_MGMT_SUPPORT SCARD_ATTR_POWER_MGMT_SUPPORT}: * Zero if device does not support power down while smart card is inserted. * <br />Nonzero otherwise. *<li>{@link SCARD_ATTR_PROTOCOL_TYPES SCARD_ATTR_PROTOCOL_TYPES}: * unsigned long encoded as 0x0rrrpppp where rrr is RFU and should be 0x000. * <br />pppp encodes the supported protocol types. A '1' in a given bit * position indicates support for the associated ISO protocol, so if bits * zero and one are set, both T=0 and T=1 protocols are supported. *<li>{@link SCARD_ATTR_VENDOR_IFD_SERIAL_NO * SCARD_ATTR_VENDOR_IFD_SERIAL_NO}: Vendor-supplied interface device serial * number. *<li>{@link SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VENDOR_IFD_TYPE}: * Vendor-supplied interface device type (model designation of reader). *<li>{@link SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VENDOR_IFD_VERSION}: * Vendor-supplied interface device version (DWORD in the form 0xMMmmbbbb * where MM = major version, mm = minor version, and bbbb = build number). *<li>{@link SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VENDOR_NAME}: Vendor name. * </ul> * * @return the attribute requested. * * @throws CardException if the card operation failed. * @throws IllegalArgumentException if a parameter is incoherent with this * function. * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. */ @Override public byte[] getAttrib(int iAttribute) throws CardException { checkSecurity("getAttrib"); checkState(); checkExclusive(); if((iAttribute == PCSCDefines.SCARD_ATTR_PROTOCOL_TYPES) && (!(System.getProperty("os.name").contains("Windows")))) { throw new CardException("org.poreid.pcscforjava." + "CardImpl.getAttrib " + "PCSCException: SCARD_E_UNSUPPORTED_FEATURE"); } try { return SCardGetAttrib(cardId, iAttribute); } catch (PCSCException ex) { throw new CardException("org.poreid.pcscforjava." + "CardImpl.getAttrib " + "PCSCException: " + ex.getMessage(), ex); } } /** * Sets an attribute of this card. * * @param iAttribute is the identifier for the attribute to set and must be: * <br /><ul><li>{@link SCARD_ATTR_SUPRESS_T1_IFS_REQUEST * SCARD_ATTR_SUPRESS_T1_IFS_REQUEST}: * Suppress sending of T=1 IFSD packet from the reader to the card. * (Can be used if the currently inserted card does not support an * IFSD request.) * @param pBCommand the new attribute for the identifier request. * * @throws CardException if the card operation failed. * @throws IllegalArgumentException if a parameter is incoherent with this * function. * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. */ @Override public void setAttrib(int iAttribute, byte[] pBCommand) throws CardException { checkSecurity("setAttrib"); if(iAttribute != SCARD_ATTR_SUPRESS_T1_IFS_REQUEST) { throw new IllegalArgumentException("Unsupported attribute " + iAttribute); } checkState(); checkExclusive(); try { SCardSetAttrib(cardId, iAttribute, pBCommand); } catch (PCSCException ex) { throw new CardException("org.poreid.pcscforjava." + "CardImpl.setAttrib " + "PCSCException: " + ex.getMessage(), ex); } } /** * Reestablish the connection with this card. After this method returns, * the connection with the card has been reseted.<br /> * The reestablishment can be of type WARM_RESET (i.e power on the card * without power off it) or COLD_RESET (i.e power on the card after * have perfoming a power off). * * @param iShareMode must be {@link SCARD_SHARE_SHARED SCARD_SHARE_SHARED} * if the reader must be in share mode or {@link SCARD_SHARE_EXCLUSIVE * SCARD_SHARE_EXCLUSIVE} if the reader must be in exclusive * mode. * @param iInitialization must be {@link SCARD_LEAVE_CARD SCARD_LEAVE_CARD} * to leave the card in its current state or {@link SCARD_RESET_CARD * SCARD_RESET_CARD} to perform a WARM_RESET to the * card of {@link SCARD_UNPOWER_CARD SCARD_UNPOWER_CARD} to perform a * COLD_RESET to the card. * * @throws CardException if the card operation failed. * @throws IllegalArgumentException if a parameter is incoherent with this * function. * @throws IllegalStateException if this card object has been disposed of * via the {@linkplain #disconnect disconnect()} method. * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission}. */ public void reconnect(int iShareMode, int iInitialization) throws CardException { byte[] _atr; checkSecurity("reconnect"); if(state != State.OK) throw new CardException("org.poreid.pcscforjava." + "CardImpl.reconnect " + "PCSCException: SCARD_W_UNPOWERED_CARD"); switch(iShareMode) { case SCARD_SHARE_SHARED: case SCARD_SHARE_EXCLUSIVE: break; default: throw new IllegalArgumentException("Unsupported share mode " + iShareMode); } switch(iInitialization) { case SCARD_LEAVE_CARD: case SCARD_RESET_CARD: case SCARD_UNPOWER_CARD: break; default: throw new IllegalArgumentException("Unsupported initialization " + iInitialization); } checkExclusive(); try { _atr = SCardReconnect(cardId, iShareMode, protocol, iInitialization); } catch (PCSCException ex) { throw new CardException("org.poreid.pcscforjava." + "CardImpl.reconnect " + "PCSCException: " + ex.getMessage(), ex); } if((_atr != null) && (_atr.length > 0)) { atr = null; try { atr = new ATR(_atr, getFrequency()); } catch (PCSCException ex) { throw new CardException("org.poreid.pcscforjava." + "CardImpl.reconnect " + "PCSCException: " + ex.getMessage(), ex); } } } /** * Returns the frequency of the smart card object. * @return the frequency of the smart card object. * @throws PCSCException if a PCSC exception occurs. */ public int getFrequency() throws PCSCException { byte[] _clockCard; int _iClockCard = 0; int _i = 0, _j = 0; try { // Get the clock card frequency in KHz _clockCard = SCardGetAttrib(cardId, SCARD_ATTR_CURRENT_CLK); } catch(PCSCException ex) { if((ex.getMessage().contains("SCARD_E_UNSUPPORTED_FEATURE")) || (ex.getMessage().contains("SCARD_E_INVALID_VALUE")) || (ex.getMessage().contains("SCARD_E_INSUFFICIENT_BUFFER"))) { // Default value is 4MHz if no possibility to know it. _clockCard = new byte[4]; _clockCard[0] = (byte) 0xA0; _clockCard[1] = (byte) 0x0F; _clockCard[2] = 0x00; _clockCard[3] = 0x00; } else throw ex; } _i = 0; while(_i < _clockCard.length) { int _iTmp = PlatformPCSC.unsignedByteToInt(_clockCard[_i]); _iClockCard += _iTmp << (_j * 8); _i++; _j++; } // Return in Hz return (_iClockCard * 1000); } /** * Prints the smart card object. * @return the smart card object description. */ @Override public String toString() { return "PC/SC card in " + terminal.getName() + ", protocol " + getProtocol() + ", state " + state; } /** * Destructor to the class. * @throws Throwable if throwable exception occurs. */ @Override protected void finalize() throws Throwable { try { if (state == State.OK) { //SCardDisconnect(cardId, SCARD_LEAVE_CARD); //this.terminal.notifyDisconnection(); } } finally { super.finalize(); } } }