undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2005, 2025, 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 javax.smartcardio;
import java.util.*;
/**
* A Smart Card's answer-to-reset bytes. A Card's ATR object can be obtained
* by calling {@linkplain Card#getATR}.
* This class does not attempt to verify that the ATR encodes a semantically
* valid structure.
*
* <p>Instances of this class are immutable. Where data is passed in or out
* via byte arrays, defensive cloning is performed.
*
* @see Card#getATR
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public final class ATR implements java.io.Serializable {
private static final long serialVersionUID = 6695383790847736493L;
/** @serial */
private byte[] atr;
private transient int startHistorical, nHistorical;
/**
* Constructs an ATR from a byte array.
*
* @param atr the byte array containing the answer-to-reset bytes
* @throws NullPointerException if <code>atr</code> is null
*/
public ATR(byte[] atr) {
this.atr = atr.clone();
parse();
}
private void parse() {
if (atr.length < 2) {
return;
}
if ((atr[0] != 0x3b) && (atr[0] != 0x3f)) {
return;
}
int t0 = (atr[1] & 0xf0) >> 4;
int n = atr[1] & 0xf;
int i = 2;
while ((t0 != 0) && (i < atr.length)) {
if ((t0 & 1) != 0) {
i++;
}
if ((t0 & 2) != 0) {
i++;
}
if ((t0 & 4) != 0) {
i++;
}
if ((t0 & 8) != 0) {
if (i >= atr.length) {
return;
}
t0 = (atr[i++] & 0xf0) >> 4;
} else {
t0 = 0;
}
}
int k = i + n;
if ((k == atr.length) || (k == atr.length - 1)) {
startHistorical = i;
nHistorical = n;
}
}
/**
* Returns a copy of the bytes in this ATR.
*
* @return a copy of the bytes in this ATR.
*/
public byte[] getBytes() {
return atr.clone();
}
/**
* Returns a copy of the historical bytes in this ATR.
* If this ATR does not contain historical bytes, an array of length
* zero is returned.
*
* @return a copy of the historical bytes in this ATR.
*/
public byte[] getHistoricalBytes() {
byte[] b = new byte[nHistorical];
System.arraycopy(atr, startHistorical, b, 0, nHistorical);
return b;
}
/**
* Returns a string representation of this ATR.
*
* @return a String representation of this ATR.
*/
public String toString() {
return "ATR: " + atr.length + " bytes";
}
/**
* Compares the specified object with this ATR for equality.
* Returns true if the given object is also an ATR and its bytes are
* identical to the bytes in this ATR.
*
* @param obj the object to be compared for equality with this ATR
* @return true if the specified object is equal to this ATR
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ATR == false) {
return false;
}
ATR other = (ATR)obj;
return Arrays.equals(this.atr, other.atr);
}
/**
* Returns the hash code value for this ATR.
*
* @return the hash code value for this ATR.
*/
public int hashCode() {
return Arrays.hashCode(atr);
}
private void readObject(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
atr = (byte[])in.readUnshared();
parse();
}
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2005, 2015, 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 javax.smartcardio;
import java.nio.ByteBuffer;
/**
* A Smart Card with which a connection has been established. Card objects
* are obtained by calling {@link CardTerminal#connect CardTerminal.connect()}.
*
* @see CardTerminal
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public abstract class Card {
/**
* 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 Card
* object.
*/
protected Card() {
// empty
}
/**
* Returns the ATR of this card.
*
* @return the ATR of this card.
*/
public abstract ATR getATR();
/**
* Returns the protocol in use for this card.
*
* @return the protocol in use for this card, for example "T=0" or "T=1"
*/
public abstract String getProtocol();
/**
* Returns the CardChannel for the basic logical channel. The basic
* logical channel has a channel number of 0.
*
* @return the 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 abstract CardChannel getBasicChannel();
/**
* 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 logical channel which has been opened
* @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 abstract CardChannel openLogicalChannel() throws CardException;
/**
* Requests exclusive access to this card.
*
* <p>Once a thread has invoked <code>beginExclusive</code>, only this
* thread is allowed to communicate with this card until it calls
* <code>endExclusive</code>. Other threads attempting communication
* will receive a CardException.
*
* <p>Applications have to ensure that exclusive access is correctly
* released. This can be achieved by executing
* the <code>beginExclusive()</code> and <code>endExclusive</code> 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 abstract void beginExclusive() throws CardException;
/**
* Releases the exclusive access previously established using
* <code>beginExclusive</code>.
*
* @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 abstract void endExclusive() throws CardException;
/**
* 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 from the terminal device
*
* @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
*/
public abstract byte[] transmitControlCommand(int controlCode,
byte[] command) throws CardException;
/**
* Disconnects the connection with this card. After this method returns,
* calling methods on this object or in CardChannels associated with this
* object that require interaction with the card will raise an
* IllegalStateException.
*
* @param reset whether to reset the card after disconnecting.
*
* @throws CardException if the card operation failed
* @throws SecurityException if a SecurityManager exists and the
* caller does not have the required
* {@linkplain CardPermission permission}
*/
public abstract void disconnect(boolean reset) throws CardException;
}

View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2005, 2013, 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 javax.smartcardio;
import java.nio.*;
/**
* A logical channel connection to a Smart Card. It is used to exchange APDUs
* with a Smart Card.
* A CardChannel object can be obtained by calling the method
* {@linkplain Card#getBasicChannel} or {@linkplain Card#openLogicalChannel}.
*
* @see Card
* @see CommandAPDU
* @see ResponseAPDU
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public abstract class CardChannel {
/**
* Constructs a new CardChannel object.
*
* <p>This constructor is called by subclasses only. Application should
* call the {@linkplain Card#getBasicChannel} and
* {@linkplain Card#openLogicalChannel} methods to obtain a CardChannel
* object.
*/
protected CardChannel() {
// empty
}
/**
* Returns the Card this channel is associated with.
*
* @return the Card this channel is associated with
*/
public abstract Card getCard();
/**
* Returns the channel number of this CardChannel. A channel number of
* 0 indicates the basic logical channel.
*
* @return the channel number of this CardChannel.
*
* @throws IllegalStateException if this channel has been
* {@linkplain #close closed} or if the corresponding Card has been
* {@linkplain Card#disconnect disconnected}.
*/
public abstract int getChannelNumber();
/**
* Transmits the specified command APDU to the Smart Card and returns the
* response APDU.
*
* <p>The CLA byte of the command APDU is automatically adjusted to
* match the channel number of this CardChannel.
*
* <p>Note that this method cannot be used to transmit
* <code>MANAGE CHANNEL</code> APDUs. Logical channels should be managed
* using the {@linkplain Card#openLogicalChannel} and {@linkplain
* CardChannel#close CardChannel.close()} methods.
*
* <p>Implementations should transparently handle artifacts
* of the transmission protocol.
* For example, when using the T=0 protocol, the following processing
* should occur as described in ISO/IEC 7816-4:
*
* <ul>
* <li><p>if the response APDU has an SW1 of <code>61</code>, the
* implementation should issue a <code>GET RESPONSE</code> command
* using <code>SW2</code> as the <code>Le</code>field.
* This process is repeated as long as an SW1 of <code>61</code> is
* received. The response body of these exchanges is concatenated
* to form the final response body.
*
* <li><p>if the response APDU is <code>6C XX</code>, the implementation
* should reissue the command using <code>XX</code> as the
* <code>Le</code> field.
* </ul>
*
* <p>The ResponseAPDU returned by this method is the result
* after this processing has been performed.
*
* @param command the command APDU
* @return the response APDU received from the card
*
* @throws IllegalStateException if this channel has been
* {@linkplain #close closed} or if the corresponding Card has been
* {@linkplain Card#disconnect disconnected}.
* @throws IllegalArgumentException if the APDU encodes a
* <code>MANAGE CHANNEL</code> command
* @throws NullPointerException if command is null
* @throws CardException if the card operation failed
*/
public abstract ResponseAPDU transmit(CommandAPDU command) throws CardException;
/**
* Transmits the command APDU stored in the command ByteBuffer and receives
* the response APDU in the response ByteBuffer.
*
* <p>The command buffer must contain valid command APDU data starting
* at <code>command.position()</code> and the APDU must be
* <code>command.remaining()</code> bytes long.
* Upon return, the command buffer's position will be equal
* to its limit; its limit will not have changed. The output buffer
* will have received the response APDU bytes. Its position will have
* advanced by the number of bytes received, which is also the return
* value of this method.
*
* <p>The CLA byte of the command APDU is automatically adjusted to
* match the channel number of this CardChannel.
*
* <p>Note that this method cannot be used to transmit
* <code>MANAGE CHANNEL</code> APDUs. Logical channels should be managed
* using the {@linkplain Card#openLogicalChannel} and {@linkplain
* CardChannel#close CardChannel.close()} methods.
*
* <p>See {@linkplain #transmit transmit()} for a discussion of the handling
* of response APDUs with the SW1 values <code>61</code> or <code>6C</code>.
*
* @param command the buffer containing the command APDU
* @param response the buffer that shall receive the response APDU from
* the card
* @return the length of the received response APDU
*
* @throws IllegalStateException if this channel has been
* {@linkplain #close closed} or if the corresponding Card has been
* {@linkplain Card#disconnect disconnected}.
* @throws NullPointerException if command or response is null
* @throws ReadOnlyBufferException if the response buffer is read-only
* @throws IllegalArgumentException if command and response are the
* same object, if <code>response</code> may not have
* sufficient space to receive the response APDU
* or if the APDU encodes a <code>MANAGE CHANNEL</code> command
* @throws CardException if the card operation failed
*/
public abstract int transmit(ByteBuffer command, ByteBuffer response)
throws CardException;
/**
* Closes this CardChannel. The logical channel is closed by issuing
* a <code>MANAGE CHANNEL</code> command that should use the format
* <code>[xx 70 80 0n]</code> where <code>n</code> is the channel number
* of this channel and <code>xx</code> is the <code>CLA</code>
* byte that encodes this logical channel and has all other bits set to 0.
* After this method returns, calling other
* methods in this class will raise an IllegalStateException.
*
* <p>Note that the basic logical channel cannot be closed using this
* method. It can be closed by calling {@link Card#disconnect}.
*
* @throws CardException if the card operation failed
* @throws IllegalStateException if this CardChannel represents a
* connection the basic logical channel
*/
public abstract void close() throws CardException;
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2005, 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 javax.smartcardio;
/**
* Exception for errors that occur during communication with the
* Smart Card stack or the card itself.
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public class CardException extends Exception {
private static final long serialVersionUID = 7787607144922050628L;
/**
* Constructs a new CardException with the specified detail message.
*
* @param message the detail message
*/
public CardException(String message) {
super(message);
}
/**
* Constructs a new CardException with the specified cause and a detail message
* of {@code (cause==null ? null : cause.toString())}.
*
* @param cause the cause of this exception or null
*/
public CardException(Throwable cause) {
super(cause);
}
/**
* Constructs a new CardException with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause of this exception or null
*/
public CardException(String message, Throwable cause) {
super(message, cause);
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2005, 2021, 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 javax.smartcardio;
/**
* Exception thrown when an application tries to establish a connection with a
* terminal that has no card present.
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public class CardNotPresentException extends CardException {
private static final long serialVersionUID = 1346879911706545215L;
/**
* Constructs a new CardNotPresentException with the specified detail message.
*
* @param message the detail message
*/
public CardNotPresentException(String message) {
super(message);
}
/**
* Constructs a new CardNotPresentException with the specified cause and a detail message
* of {@code (cause==null ? null : cause.toString())}.
*
* @param cause the cause of this exception or null
*/
public CardNotPresentException(Throwable cause) {
super(cause);
}
/**
* Constructs a new CardNotPresentException with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause of this exception or null
*/
public CardNotPresentException(String message, Throwable cause) {
super(message, cause);
}
}

View file

@ -0,0 +1,294 @@
/*
* Copyright (c) 2005, 2021, 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 javax.smartcardio;
import java.io.*;
import java.util.StringJoiner;
import java.security.Permission;
/**
* A permission for Smart Card operations. A CardPermission consists of the
* name of the card terminal the permission applies to and a set of actions
* that are valid for that terminal.
*
* <p>A CardPermission with a name of <code>*</code> applies to all
* card terminals. The actions string is a comma separated list of the actions
* listed below, or <code>*</code> to signify "all actions."
*
* <p>Individual actions are:
* <dl>
* <dt>connect
* <dd>connect to a card using
* {@linkplain CardTerminal#connect CardTerminal.connect()}
*
* <dt>reset
* <dd>reset the card using {@linkplain Card#disconnect Card.disconnect(true)}
*
* <dt>exclusive
* <dd>establish exclusive access to a card using
* {@linkplain Card#beginExclusive} and {@linkplain Card#endExclusive
* endExclusive()}
*
* <dt>transmitControl
* <dd>transmit a control command using
* {@linkplain Card#transmitControlCommand Card.transmitControlCommand()}
*
* <dt>getBasicChannel
* <dd>obtain the basic logical channel using
* {@linkplain Card#getBasicChannel}
*
* <dt>openLogicalChannel
* <dd>open a new logical channel using
* {@linkplain Card#openLogicalChannel}
*
* </dl>
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public class CardPermission extends Permission {
private static final long serialVersionUID = 7146787880530705613L;
private static final int A_CONNECT = 0x01;
private static final int A_EXCLUSIVE = 0x02;
private static final int A_GET_BASIC_CHANNEL = 0x04;
private static final int A_OPEN_LOGICAL_CHANNEL = 0x08;
private static final int A_RESET = 0x10;
private static final int A_TRANSMIT_CONTROL = 0x20;
// sum of all the actions above
private static final int A_ALL = 0x3f;
private static final int[] ARRAY_MASKS = {
A_ALL,
A_CONNECT,
A_EXCLUSIVE,
A_GET_BASIC_CHANNEL,
A_OPEN_LOGICAL_CHANNEL,
A_RESET,
A_TRANSMIT_CONTROL,
};
private static final String S_CONNECT = "connect";
private static final String S_EXCLUSIVE = "exclusive";
private static final String S_GET_BASIC_CHANNEL = "getBasicChannel";
private static final String S_OPEN_LOGICAL_CHANNEL = "openLogicalChannel";
private static final String S_RESET = "reset";
private static final String S_TRANSMIT_CONTROL = "transmitControl";
private static final String S_ALL = "*";
private static final String[] ARRAY_STRINGS = {
S_ALL,
S_CONNECT,
S_EXCLUSIVE,
S_GET_BASIC_CHANNEL,
S_OPEN_LOGICAL_CHANNEL,
S_RESET,
S_TRANSMIT_CONTROL,
};
private transient int mask;
/**
* @serial
*/
private final String actions;
/**
* Constructs a new CardPermission with the specified actions.
* <code>terminalName</code> is the name of a CardTerminal or <code>*</code>
* if this permission applies to all terminals. <code>actions</code>
* contains a comma-separated list of the individual actions
* or <code>*</code> to signify all actions. For more information,
* see the documentation at the top of this {@linkplain CardPermission
* class}.
*
* @param terminalName the name of the card terminal, or <code>*</code>
* @param actions the action string (or null if the set of permitted
* actions is empty)
*
* @throws NullPointerException if terminalName is null
* @throws IllegalArgumentException if actions is an invalid actions
* specification
*/
public CardPermission(String terminalName, String actions) {
super(terminalName);
if (terminalName == null) {
throw new NullPointerException();
}
mask = getMask(actions);
this.actions = getActions(mask);
}
private static int getMask(String actions) {
if (actions == null) {
return 0;
}
if (actions.length() == 0) {
throw new IllegalArgumentException("actions must not be empty");
}
// try exact matches for simple actions first
for (int i = 0; i < ARRAY_STRINGS.length; i++) {
if (actions == ARRAY_STRINGS[i]) {
return ARRAY_MASKS[i];
}
}
if (actions.endsWith(",")) {
throw new IllegalArgumentException("Invalid actions: '" + actions + "'");
}
int mask = 0;
String[] split = actions.split(",");
outer:
for (String s : split) {
for (int i = 0; i < ARRAY_STRINGS.length; i++) {
if (ARRAY_STRINGS[i].equalsIgnoreCase(s)) {
mask |= ARRAY_MASKS[i];
continue outer;
}
}
throw new IllegalArgumentException("Invalid action: '" + s + "'");
}
return mask;
}
private static String getActions(int mask) {
if (mask == 0) {
return null;
}
if (mask == A_ALL) {
return S_ALL;
}
StringJoiner sj = new StringJoiner(",");
for (int i = 0; i < ARRAY_MASKS.length; i++) {
final int action = ARRAY_MASKS[i];
if ((mask & action) == action) {
sj.add(ARRAY_STRINGS[i]);
}
}
return sj.toString();
}
/**
* Returns the canonical string representation of the actions.
* It is <code>*</code> to signify all actions defined by this class or
* the string concatenation of the comma-separated,
* lexicographically sorted list of individual actions.
*
* @return the canonical string representation of the actions.
*/
public String getActions() {
return actions;
}
/**
* Checks if this CardPermission object implies the specified permission.
* That is the case, if and only if
* <ul>
* <li><p><code>permission</code> is an instance of CardPermission,</p>
* <li><p><code>permission</code>'s actions are a proper subset of this
* object's actions, and</p>
* <li><p>this object's <code>getName()</code> method is either
* <code>*</code> or equal to <code>permission</code>'s <code>name</code>.
* </p>
* </ul>
*
* @param permission the permission to check against
* @return true if and only if this CardPermission object implies the
* specified permission.
*/
public boolean implies(Permission permission) {
if (permission instanceof CardPermission == false) {
return false;
}
CardPermission other = (CardPermission)permission;
if ((this.mask & other.mask) != other.mask) {
return false;
}
String thisName = getName();
if (thisName.equals("*")) {
return true;
}
if (thisName.equals(other.getName())) {
return true;
}
return false;
}
/**
* Compares the specified object with this CardPermission for equality.
* This CardPermission is equal to another Object <code>object</code>, if
* and only if
* <ul>
* <li><p><code>object</code> is an instance of CardPermission,</p>
* <li><p><code>this.getName()</code> is equal to
* <code>((CardPermission)object).getName()</code>, and</p>
* <li><p><code>this.getActions()</code> is equal to
* <code>((CardPermission)object).getActions()</code>.</p>
* </ul>
*
* @param obj the object to be compared for equality with this CardPermission
* @return true if and only if the specified object is equal to this
* CardPermission
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof CardPermission == false) {
return false;
}
CardPermission other = (CardPermission)obj;
return this.getName().equals(other.getName()) && (this.mask == other.mask);
}
/**
* Returns the hash code value for this CardPermission object.
*
* @return the hash code value for this CardPermission object.
*/
public int hashCode() {
return getName().hashCode() + 31 * mask;
}
private void writeObject(ObjectOutputStream s) throws IOException {
// Write out the actions. The superclass takes care of the name.
s.defaultWriteObject();
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
// Read in the actions, then restore the mask.
s.defaultReadObject();
mask = getMask(actions);
}
}

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2005, 2015, 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 javax.smartcardio;
import java.util.*;
/**
* A Smart Card terminal, sometimes referred to as a Smart Card Reader.
* A CardTerminal object can be obtained by calling
* {@linkplain CardTerminals#list}
* or {@linkplain CardTerminals#getTerminal CardTerminals.getTerminal()}.
*
* <p>Note that physical card readers with slots for multiple cards are
* represented by one <code>CardTerminal</code> object per such slot.
*
* @see CardTerminals
* @see TerminalFactory
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public abstract class CardTerminal {
/**
* Constructs a new CardTerminal object.
*
* <p>This constructor is called by subclasses only. Application should
* call {@linkplain CardTerminals#list list()}
* or {@linkplain CardTerminals#getTerminal getTerminal()}
* to obtain a CardTerminal object.
*/
protected CardTerminal() {
// empty
}
/**
* Returns the unique name of this terminal.
*
* @return the unique name of this terminal.
*/
public abstract String getName();
/**
* Establishes a connection to the card.
* If a connection has previously established using
* the specified protocol, this method returns the same Card object as
* the previous call.
*
* @param protocol the protocol to use ("T=0", "T=1", or "T=CL"), or "*" to
* connect using any available protocol.
*
* @throws NullPointerException if protocol is null
* @throws IllegalArgumentException if protocol is an invalid protocol
* specification
* @throws CardNotPresentException if no card is present in this terminal
* @throws CardException if a connection could not be established
* using the specified protocol or if a connection has previously been
* established using a different protocol
* @throws SecurityException if a SecurityManager exists and the
* caller does not have the required
* {@linkplain CardPermission permission}
* @return the card the connection has been established with
*/
public abstract Card connect(String protocol) throws CardException;
/**
* Returns whether a card is present in this terminal.
*
* @return whether a card is present in this terminal.
*
* @throws CardException if the status could not be determined
*/
public abstract boolean isCardPresent() throws CardException;
/**
* Waits until a card is present in this terminal or the timeout
* expires. If the method returns due to an expired timeout, it returns
* false. Otherwise it return true.
*
* <P>If a card is present in this terminal when this
* method is called, it returns immediately.
*
* @param timeout if positive, block for up to <code>timeout</code>
* milliseconds; if zero, block indefinitely; must not be negative
* @return false if the method returns due to an expired timeout,
* true otherwise.
*
* @throws IllegalArgumentException if timeout is negative
* @throws CardException if the operation failed
*/
public abstract boolean waitForCardPresent(long timeout) throws CardException;
/**
* Waits until a card is absent in this terminal or the timeout
* expires. If the method returns due to an expired timeout, it returns
* false. Otherwise it return true.
*
* <P>If no card is present in this terminal when this
* method is called, it returns immediately.
*
* @param timeout if positive, block for up to <code>timeout</code>
* milliseconds; if zero, block indefinitely; must not be negative
* @return false if the method returns due to an expired timeout,
* true otherwise.
*
* @throws IllegalArgumentException if timeout is negative
* @throws CardException if the operation failed
*/
public abstract boolean waitForCardAbsent(long timeout) throws CardException;
}

View file

@ -0,0 +1,218 @@
/*
* Copyright (c) 2006, 2023, 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 javax.smartcardio;
import java.util.*;
/**
* The set of terminals supported by a TerminalFactory.
* This class allows applications to enumerate the available CardTerminals,
* obtain a specific CardTerminal, or wait for the insertion or removal of
* cards.
*
* <p>This class is multi-threading safe and can be used by multiple
* threads concurrently. However, this object keeps track of the card
* presence state of each of its terminals. Multiple objects should be used
* if independent calls to {@linkplain #waitForChange} are required.
*
* <p>Applications can obtain instances of this class by calling
* {@linkplain TerminalFactory#terminals}.
*
* @see TerminalFactory
* @see CardTerminal
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public abstract class CardTerminals {
/**
* Constructs a new CardTerminals object.
*
* <p>This constructor is called by subclasses only. Application should
* call {@linkplain TerminalFactory#terminals}
* to obtain a CardTerminals object.
*/
protected CardTerminals() {
// empty
}
/**
* Returns an unmodifiable list of all available terminals.
*
* @return an unmodifiable list of all available terminals.
*
* @throws CardException if the card operation failed
*/
public List<CardTerminal> list() throws CardException {
return list(State.ALL);
}
/**
* Returns an unmodifiable list of all terminals matching the specified
* state.
*
* <p>If state is {@link State#ALL State.ALL}, this method returns
* all CardTerminals encapsulated by this object.
* If state is {@link State#CARD_PRESENT State.CARD_PRESENT} or
* {@link State#CARD_ABSENT State.CARD_ABSENT}, it returns all
* CardTerminals where a card is currently present or absent, respectively.
*
* <p>If state is {@link State#CARD_INSERTION State.CARD_INSERTION} or
* {@link State#CARD_REMOVAL State.CARD_REMOVAL}, it returns all
* CardTerminals for which an insertion (or removal, respectively)
* was detected during the last call to {@linkplain #waitForChange}.
* If <code>waitForChange()</code> has not been called on this object,
* <code>CARD_INSERTION</code> is equivalent to <code>CARD_PRESENT</code>
* and <code>CARD_REMOVAL</code> is equivalent to <code>CARD_ABSENT</code>.
* For an example of the use of <code>CARD_INSERTION</code>,
* see {@link #waitForChange}.
*
* @param state the State
* @return an unmodifiable list of all terminals matching the specified
* state.
*
* @throws NullPointerException if state is null
* @throws CardException if the card operation failed
*/
public abstract List<CardTerminal> list(State state) throws CardException;
/**
* Returns the terminal with the specified name or null if no such
* terminal exists.
*
* @param name the terminal name
* @return the terminal with the specified name or null if no such
* terminal exists.
*
* @throws NullPointerException if name is null
*/
public CardTerminal getTerminal(String name) {
if (name == null) {
throw new NullPointerException();
}
try {
for (CardTerminal terminal : list()) {
if (terminal.getName().equals(name)) {
return terminal;
}
}
return null;
} catch (CardException e) {
return null;
}
}
/**
* Waits for card insertion or removal in any of the terminals of this
* object.
*
* <p>This call is equivalent to calling
* {@linkplain #waitForChange(long) waitForChange(0)}.
*
* @throws IllegalStateException if this <code>CardTerminals</code>
* object does not contain any terminals
* @throws CardException if the card operation failed
*/
public void waitForChange() throws CardException {
waitForChange(0);
}
/**
* Waits for card insertion or removal in any of the terminals of this
* object or until the timeout expires.
*
* <p>This method examines each CardTerminal of this object.
* If a card was inserted into or removed from a CardTerminal since the
* previous call to <code>waitForChange()</code>, it returns
* immediately.
* Otherwise, or if this is the first call to <code>waitForChange()</code>
* on this object, it blocks until a card is inserted into or removed from
* a CardTerminal.
*
* <p>If <code>timeout</code> is greater than 0, the method returns after
* <code>timeout</code> milliseconds even if there is no change in state.
* In that case, this method returns <code>false</code>; otherwise it
* returns <code>true</code>.
*
* <p>This method is often used in a loop in combination with
* {@link #list(CardTerminals.State) list(State.CARD_INSERTION)},
* for example:
* <pre>
* TerminalFactory factory = ...;
* CardTerminals terminals = factory.terminals();
* while (true) {
* for (CardTerminal terminal : terminals.list(CARD_INSERTION)) {
* // examine Card in terminal, return if it matches
* }
* terminals.waitForChange();
* }</pre>
*
* @param timeout if positive, block for up to <code>timeout</code>
* milliseconds; if zero, block indefinitely; must not be negative
* @return false if the method returns due to an expired timeout,
* true otherwise.
*
* @throws IllegalStateException if this <code>CardTerminals</code>
* object does not contain any terminals
* @throws IllegalArgumentException if timeout is negative
* @throws CardException if the card operation failed
*/
public abstract boolean waitForChange(long timeout) throws CardException;
/**
* Enumeration of attributes of a CardTerminal.
* It is used as a parameter to the {@linkplain CardTerminals#list} method.
*
* @since 1.6
*/
public static enum State {
/**
* All CardTerminals.
*/
ALL,
/**
* CardTerminals in which a card is present.
*/
CARD_PRESENT,
/**
* CardTerminals in which a card is not present.
*/
CARD_ABSENT,
/**
* CardTerminals for which a card insertion was detected during the
* latest call to {@linkplain CardTerminals#waitForChange() waitForChange()}.
*/
CARD_INSERTION,
/**
* CardTerminals for which a card removal was detected during the
* latest call to {@linkplain CardTerminals#waitForChange() waitForChange()}.
*/
CARD_REMOVAL,
}
}

View file

@ -0,0 +1,606 @@
/*
* Copyright (c) 2005, 2006, 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 javax.smartcardio;
import java.util.Arrays;
import java.nio.ByteBuffer;
/**
* A command APDU following the structure defined in ISO/IEC 7816-4.
* It consists of a four byte header and a conditional body of variable length.
* This class does not attempt to verify that the APDU encodes a semantically
* valid command.
*
* <p>Note that when the expected length of the response APDU is specified
* in the {@linkplain #CommandAPDU(int,int,int,int,int) constructors},
* the actual length (Ne) must be specified, not its
* encoded form (Le). Similarly, {@linkplain #getNe} returns the actual
* value Ne. In other words, a value of 0 means "no data in the response APDU"
* rather than "maximum length."
*
* <p>This class supports both the short and extended forms of length
* encoding for Ne and Nc. However, note that not all terminals and Smart Cards
* are capable of accepting APDUs that use the extended form.
*
* <p>For the header bytes CLA, INS, P1, and P2 the Java type <code>int</code>
* is used to represent the 8 bit unsigned values. In the constructors, only
* the 8 lowest bits of the <code>int</code> value specified by the application
* are significant. The accessor methods always return the byte as an unsigned
* value between 0 and 255.
*
* <p>Instances of this class are immutable. Where data is passed in or out
* via byte arrays, defensive cloning is performed.
*
* @see ResponseAPDU
* @see CardChannel#transmit CardChannel.transmit
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public final class CommandAPDU implements java.io.Serializable {
private static final long serialVersionUID = 398698301286670877L;
private static final int MAX_APDU_SIZE = 65544;
/** @serial */
private byte[] apdu;
// value of nc
private transient int nc;
// value of ne
private transient int ne;
// index of start of data within the apdu array
private transient int dataOffset;
/**
* Constructs a CommandAPDU from a byte array containing the complete
* APDU contents (header and body).
*
* <p>Note that the apdu bytes are copied to protect against
* subsequent modification.
*
* @param apdu the complete command APDU
*
* @throws NullPointerException if apdu is null
* @throws IllegalArgumentException if apdu does not contain a valid
* command APDU
*/
public CommandAPDU(byte[] apdu) {
this.apdu = apdu.clone();
parse();
}
/**
* Constructs a CommandAPDU from a byte array containing the complete
* APDU contents (header and body). The APDU starts at the index
* <code>apduOffset</code> in the byte array and is <code>apduLength</code>
* bytes long.
*
* <p>Note that the apdu bytes are copied to protect against
* subsequent modification.
*
* @param apdu the complete command APDU
* @param apduOffset the offset in the byte array at which the apdu
* data begins
* @param apduLength the length of the APDU
*
* @throws NullPointerException if apdu is null
* @throws IllegalArgumentException if apduOffset or apduLength are
* negative or if apduOffset + apduLength are greater than apdu.length,
* or if the specified bytes are not a valid APDU
*/
public CommandAPDU(byte[] apdu, int apduOffset, int apduLength) {
checkArrayBounds(apdu, apduOffset, apduLength);
this.apdu = new byte[apduLength];
System.arraycopy(apdu, apduOffset, this.apdu, 0, apduLength);
parse();
}
private void checkArrayBounds(byte[] b, int ofs, int len) {
if ((ofs < 0) || (len < 0)) {
throw new IllegalArgumentException
("Offset and length must not be negative");
}
if (b == null) {
if ((ofs != 0) && (len != 0)) {
throw new IllegalArgumentException
("offset and length must be 0 if array is null");
}
} else {
if (ofs > b.length - len) {
throw new IllegalArgumentException
("Offset plus length exceed array size");
}
}
}
/**
* Creates a CommandAPDU from the ByteBuffer containing the complete APDU
* contents (header and body).
* The buffer's <code>position</code> must be set to the start of the APDU,
* its <code>limit</code> to the end of the APDU. Upon return, the buffer's
* <code>position</code> is equal to its limit; its limit remains unchanged.
*
* <p>Note that the data in the ByteBuffer is copied to protect against
* subsequent modification.
*
* @param apdu the ByteBuffer containing the complete APDU
*
* @throws NullPointerException if apdu is null
* @throws IllegalArgumentException if apdu does not contain a valid
* command APDU
*/
public CommandAPDU(ByteBuffer apdu) {
this.apdu = new byte[apdu.remaining()];
apdu.get(this.apdu);
parse();
}
/**
* Constructs a CommandAPDU from the four header bytes. This is case 1
* in ISO 7816, no command body.
*
* @param cla the class byte CLA
* @param ins the instruction byte INS
* @param p1 the parameter byte P1
* @param p2 the parameter byte P2
*/
public CommandAPDU(int cla, int ins, int p1, int p2) {
this(cla, ins, p1, p2, null, 0, 0, 0);
}
/**
* Constructs a CommandAPDU from the four header bytes and the expected
* response data length. This is case 2 in ISO 7816, empty command data
* field with Ne specified. If Ne is 0, the APDU is encoded as ISO 7816
* case 1.
*
* @param cla the class byte CLA
* @param ins the instruction byte INS
* @param p1 the parameter byte P1
* @param p2 the parameter byte P2
* @param ne the maximum number of expected data bytes in a response APDU
*
* @throws IllegalArgumentException if ne is negative or greater than
* 65536
*/
public CommandAPDU(int cla, int ins, int p1, int p2, int ne) {
this(cla, ins, p1, p2, null, 0, 0, ne);
}
/**
* Constructs a CommandAPDU from the four header bytes and command data.
* This is case 3 in ISO 7816, command data present and Ne absent. The
* value Nc is taken as data.length. If <code>data</code> is null or
* its length is 0, the APDU is encoded as ISO 7816 case 1.
*
* <p>Note that the data bytes are copied to protect against
* subsequent modification.
*
* @param cla the class byte CLA
* @param ins the instruction byte INS
* @param p1 the parameter byte P1
* @param p2 the parameter byte P2
* @param data the byte array containing the data bytes of the command body
*
* @throws IllegalArgumentException if data.length is greater than 65535
*/
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data) {
this(cla, ins, p1, p2, data, 0, arrayLength(data), 0);
}
/**
* Constructs a CommandAPDU from the four header bytes and command data.
* This is case 3 in ISO 7816, command data present and Ne absent. The
* value Nc is taken as dataLength. If <code>dataLength</code>
* is 0, the APDU is encoded as ISO 7816 case 1.
*
* <p>Note that the data bytes are copied to protect against
* subsequent modification.
*
* @param cla the class byte CLA
* @param ins the instruction byte INS
* @param p1 the parameter byte P1
* @param p2 the parameter byte P2
* @param data the byte array containing the data bytes of the command body
* @param dataOffset the offset in the byte array at which the data
* bytes of the command body begin
* @param dataLength the number of the data bytes in the command body
*
* @throws NullPointerException if data is null and dataLength is not 0
* @throws IllegalArgumentException if dataOffset or dataLength are
* negative or if dataOffset + dataLength are greater than data.length
* or if dataLength is greater than 65535
*/
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
int dataOffset, int dataLength) {
this(cla, ins, p1, p2, data, dataOffset, dataLength, 0);
}
/**
* Constructs a CommandAPDU from the four header bytes, command data,
* and expected response data length. This is case 4 in ISO 7816,
* command data and Ne present. The value Nc is taken as data.length
* if <code>data</code> is non-null and as 0 otherwise. If Ne or Nc
* are zero, the APDU is encoded as case 1, 2, or 3 per ISO 7816.
*
* <p>Note that the data bytes are copied to protect against
* subsequent modification.
*
* @param cla the class byte CLA
* @param ins the instruction byte INS
* @param p1 the parameter byte P1
* @param p2 the parameter byte P2
* @param data the byte array containing the data bytes of the command body
* @param ne the maximum number of expected data bytes in a response APDU
*
* @throws IllegalArgumentException if data.length is greater than 65535
* or if ne is negative or greater than 65536
*/
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int ne) {
this(cla, ins, p1, p2, data, 0, arrayLength(data), ne);
}
private static int arrayLength(byte[] b) {
return (b != null) ? b.length : 0;
}
/**
* Command APDU encoding options:
*
* case 1: |CLA|INS|P1 |P2 | len = 4
* case 2s: |CLA|INS|P1 |P2 |LE | len = 5
* case 3s: |CLA|INS|P1 |P2 |LC |...BODY...| len = 6..260
* case 4s: |CLA|INS|P1 |P2 |LC |...BODY...|LE | len = 7..261
* case 2e: |CLA|INS|P1 |P2 |00 |LE1|LE2| len = 7
* case 3e: |CLA|INS|P1 |P2 |00 |LC1|LC2|...BODY...| len = 8..65542
* case 4e: |CLA|INS|P1 |P2 |00 |LC1|LC2|...BODY...|LE1|LE2| len =10..65544
*
* LE, LE1, LE2 may be 0x00.
* LC must not be 0x00 and LC1|LC2 must not be 0x00|0x00
*/
private void parse() {
if (apdu.length < 4) {
throw new IllegalArgumentException("apdu must be at least 4 bytes long");
}
if (apdu.length == 4) {
// case 1
return;
}
int l1 = apdu[4] & 0xff;
if (apdu.length == 5) {
// case 2s
this.ne = (l1 == 0) ? 256 : l1;
return;
}
if (l1 != 0) {
if (apdu.length == 4 + 1 + l1) {
// case 3s
this.nc = l1;
this.dataOffset = 5;
return;
} else if (apdu.length == 4 + 2 + l1) {
// case 4s
this.nc = l1;
this.dataOffset = 5;
int l2 = apdu[apdu.length - 1] & 0xff;
this.ne = (l2 == 0) ? 256 : l2;
return;
} else {
throw new IllegalArgumentException
("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
}
}
if (apdu.length < 7) {
throw new IllegalArgumentException
("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
}
int l2 = ((apdu[5] & 0xff) << 8) | (apdu[6] & 0xff);
if (apdu.length == 7) {
// case 2e
this.ne = (l2 == 0) ? 65536 : l2;
return;
}
if (l2 == 0) {
throw new IllegalArgumentException("Invalid APDU: length="
+ apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
}
if (apdu.length == 4 + 3 + l2) {
// case 3e
this.nc = l2;
this.dataOffset = 7;
return;
} else if (apdu.length == 4 + 5 + l2) {
// case 4e
this.nc = l2;
this.dataOffset = 7;
int leOfs = apdu.length - 2;
int l3 = ((apdu[leOfs] & 0xff) << 8) | (apdu[leOfs + 1] & 0xff);
this.ne = (l3 == 0) ? 65536 : l3;
} else {
throw new IllegalArgumentException("Invalid APDU: length="
+ apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
}
}
/**
* Constructs a CommandAPDU from the four header bytes, command data,
* and expected response data length. This is case 4 in ISO 7816,
* command data and Le present. The value Nc is taken as
* <code>dataLength</code>.
* If Ne or Nc
* are zero, the APDU is encoded as case 1, 2, or 3 per ISO 7816.
*
* <p>Note that the data bytes are copied to protect against
* subsequent modification.
*
* @param cla the class byte CLA
* @param ins the instruction byte INS
* @param p1 the parameter byte P1
* @param p2 the parameter byte P2
* @param data the byte array containing the data bytes of the command body
* @param dataOffset the offset in the byte array at which the data
* bytes of the command body begin
* @param dataLength the number of the data bytes in the command body
* @param ne the maximum number of expected data bytes in a response APDU
*
* @throws NullPointerException if data is null and dataLength is not 0
* @throws IllegalArgumentException if dataOffset or dataLength are
* negative or if dataOffset + dataLength are greater than data.length,
* or if ne is negative or greater than 65536,
* or if dataLength is greater than 65535
*/
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
int dataOffset, int dataLength, int ne) {
checkArrayBounds(data, dataOffset, dataLength);
if (dataLength > 65535) {
throw new IllegalArgumentException("dataLength is too large");
}
if (ne < 0) {
throw new IllegalArgumentException("ne must not be negative");
}
if (ne > 65536) {
throw new IllegalArgumentException("ne is too large");
}
this.ne = ne;
this.nc = dataLength;
if (dataLength == 0) {
if (ne == 0) {
// case 1
this.apdu = new byte[4];
setHeader(cla, ins, p1, p2);
} else {
// case 2s or 2e
if (ne <= 256) {
// case 2s
// 256 is encoded as 0x00
byte len = (ne != 256) ? (byte)ne : 0;
this.apdu = new byte[5];
setHeader(cla, ins, p1, p2);
this.apdu[4] = len;
} else {
// case 2e
byte l1, l2;
// 65536 is encoded as 0x00 0x00
if (ne == 65536) {
l1 = 0;
l2 = 0;
} else {
l1 = (byte)(ne >> 8);
l2 = (byte)ne;
}
this.apdu = new byte[7];
setHeader(cla, ins, p1, p2);
this.apdu[5] = l1;
this.apdu[6] = l2;
}
}
} else {
if (ne == 0) {
// case 3s or 3e
if (dataLength <= 255) {
// case 3s
apdu = new byte[4 + 1 + dataLength];
setHeader(cla, ins, p1, p2);
apdu[4] = (byte)dataLength;
this.dataOffset = 5;
System.arraycopy(data, dataOffset, apdu, 5, dataLength);
} else {
// case 3e
apdu = new byte[4 + 3 + dataLength];
setHeader(cla, ins, p1, p2);
apdu[4] = 0;
apdu[5] = (byte)(dataLength >> 8);
apdu[6] = (byte)dataLength;
this.dataOffset = 7;
System.arraycopy(data, dataOffset, apdu, 7, dataLength);
}
} else {
// case 4s or 4e
if ((dataLength <= 255) && (ne <= 256)) {
// case 4s
apdu = new byte[4 + 2 + dataLength];
setHeader(cla, ins, p1, p2);
apdu[4] = (byte)dataLength;
this.dataOffset = 5;
System.arraycopy(data, dataOffset, apdu, 5, dataLength);
apdu[apdu.length - 1] = (ne != 256) ? (byte)ne : 0;
} else {
// case 4e
apdu = new byte[4 + 5 + dataLength];
setHeader(cla, ins, p1, p2);
apdu[4] = 0;
apdu[5] = (byte)(dataLength >> 8);
apdu[6] = (byte)dataLength;
this.dataOffset = 7;
System.arraycopy(data, dataOffset, apdu, 7, dataLength);
if (ne != 65536) {
int leOfs = apdu.length - 2;
apdu[leOfs] = (byte)(ne >> 8);
apdu[leOfs + 1] = (byte)ne;
} // else le == 65536: no need to fill in, encoded as 0
}
}
}
}
private void setHeader(int cla, int ins, int p1, int p2) {
apdu[0] = (byte)cla;
apdu[1] = (byte)ins;
apdu[2] = (byte)p1;
apdu[3] = (byte)p2;
}
/**
* Returns the value of the class byte CLA.
*
* @return the value of the class byte CLA.
*/
public int getCLA() {
return apdu[0] & 0xff;
}
/**
* Returns the value of the instruction byte INS.
*
* @return the value of the instruction byte INS.
*/
public int getINS() {
return apdu[1] & 0xff;
}
/**
* Returns the value of the parameter byte P1.
*
* @return the value of the parameter byte P1.
*/
public int getP1() {
return apdu[2] & 0xff;
}
/**
* Returns the value of the parameter byte P2.
*
* @return the value of the parameter byte P2.
*/
public int getP2() {
return apdu[3] & 0xff;
}
/**
* Returns the number of data bytes in the command body (Nc) or 0 if this
* APDU has no body. This call is equivalent to
* <code>getData().length</code>.
*
* @return the number of data bytes in the command body or 0 if this APDU
* has no body.
*/
public int getNc() {
return nc;
}
/**
* Returns a copy of the data bytes in the command body. If this APDU as
* no body, this method returns a byte array with length zero.
*
* @return a copy of the data bytes in the command body or the empty
* byte array if this APDU has no body.
*/
public byte[] getData() {
byte[] data = new byte[nc];
System.arraycopy(apdu, dataOffset, data, 0, nc);
return data;
}
/**
* Returns the maximum number of expected data bytes in a response
* APDU (Ne).
*
* @return the maximum number of expected data bytes in a response APDU.
*/
public int getNe() {
return ne;
}
/**
* Returns a copy of the bytes in this APDU.
*
* @return a copy of the bytes in this APDU.
*/
public byte[] getBytes() {
return apdu.clone();
}
/**
* Returns a string representation of this command APDU.
*
* @return a String representation of this command APDU.
*/
public String toString() {
return "CommmandAPDU: " + apdu.length + " bytes, nc=" + nc + ", ne=" + ne;
}
/**
* Compares the specified object with this command APDU for equality.
* Returns true if the given object is also a CommandAPDU and its bytes are
* identical to the bytes in this CommandAPDU.
*
* @param obj the object to be compared for equality with this command APDU
* @return true if the specified object is equal to this command APDU
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof CommandAPDU == false) {
return false;
}
CommandAPDU other = (CommandAPDU)obj;
return Arrays.equals(this.apdu, other.apdu);
}
/**
* Returns the hash code value for this command APDU.
*
* @return the hash code value for this command APDU.
*/
public int hashCode() {
return Arrays.hashCode(apdu);
}
private void readObject(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
apdu = (byte[])in.readUnshared();
// initialize transient fields
parse();
}
}

View file

@ -0,0 +1,185 @@
/*
* Copyright (c) 2005, 2022, 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 javax.smartcardio;
import java.util.Arrays;
/**
* A response APDU as defined in ISO/IEC 7816-4. It consists of a conditional
* body and a two byte trailer.
* This class does not attempt to verify that the APDU encodes a semantically
* valid response.
*
* <p>Instances of this class are immutable. Where data is passed in or out
* via byte arrays, defensive cloning is performed.
*
* @see CommandAPDU
* @see CardChannel#transmit CardChannel.transmit
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public final class ResponseAPDU implements java.io.Serializable {
private static final long serialVersionUID = 6962744978375594225L;
/** @serial */
private byte[] apdu;
/**
* Constructs a ResponseAPDU from a byte array containing the complete
* APDU contents (conditional body and trailed).
*
* <p>Note that the byte array is cloned to protect against subsequent
* modification.
*
* @param apdu the complete response APDU
*
* @throws NullPointerException if apdu is null
* @throws IllegalArgumentException if apdu.length is less than 2
*/
public ResponseAPDU(byte[] apdu) {
apdu = apdu.clone();
check(apdu);
this.apdu = apdu;
}
private static void check(byte[] apdu) {
if (apdu.length < 2) {
throw new IllegalArgumentException("apdu must be at least 2 bytes long");
}
}
/**
* Returns the number of data bytes in the response body (Nr) or 0 if this
* APDU has no body. This call is equivalent to
* <code>getData().length</code>.
*
* @return the number of data bytes in the response body or 0 if this APDU
* has no body.
*/
public int getNr() {
return apdu.length - 2;
}
/**
* Returns a copy of the data bytes in the response body. If this APDU has
* no body, this method returns a byte array with a length of zero.
*
* @return a copy of the data bytes in the response body or the empty
* byte array if this APDU has no body.
*/
public byte[] getData() {
byte[] data = new byte[apdu.length - 2];
System.arraycopy(apdu, 0, data, 0, data.length);
return data;
}
/**
* Returns the value of the status byte SW1 as a value between 0 and 255.
*
* @return the value of the status byte SW1 as a value between 0 and 255.
*/
public int getSW1() {
return apdu[apdu.length - 2] & 0xff;
}
/**
* Returns the value of the status byte SW2 as a value between 0 and 255.
*
* @return the value of the status byte SW2 as a value between 0 and 255.
*/
public int getSW2() {
return apdu[apdu.length - 1] & 0xff;
}
/**
* Returns the value of the status bytes SW1 and SW2 as a single
* status word SW.
* It is defined as
* {@code (getSW1() << 8) | getSW2()}
*
* @return the value of the status word SW.
*/
public int getSW() {
return (getSW1() << 8) | getSW2();
}
/**
* Returns a copy of the bytes in this APDU.
*
* @return a copy of the bytes in this APDU.
*/
public byte[] getBytes() {
return apdu.clone();
}
/**
* Returns a string representation of this response APDU.
*
* @return a String representation of this response APDU.
*/
public String toString() {
return "ResponseAPDU: " + apdu.length + " bytes, SW="
+ Integer.toHexString(getSW());
}
/**
* Compares the specified object with this response APDU for equality.
* Returns true if the given object is also a ResponseAPDU and its bytes are
* identical to the bytes in this ResponseAPDU.
*
* @param obj the object to be compared for equality with this response APDU
* @return true if the specified object is equal to this response APDU
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ResponseAPDU == false) {
return false;
}
ResponseAPDU other = (ResponseAPDU)obj;
return Arrays.equals(this.apdu, other.apdu);
}
/**
* Returns the hash code value for this response APDU.
*
* @return the hash code value for this response APDU.
*/
public int hashCode() {
return Arrays.hashCode(apdu);
}
private void readObject(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
apdu = (byte[])in.readUnshared();
check(apdu);
}
}

View file

@ -0,0 +1,372 @@
/*
* Copyright (c) 2005, 2021, 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 javax.smartcardio;
import java.util.*;
import java.security.*;
import sun.security.jca.*;
import sun.security.jca.GetInstance.*;
/**
* A factory for CardTerminal objects.
*
* It allows an application to
* <ul>
* <li>obtain a TerminalFactory by calling
* one of the static factory methods in this class
* ({@linkplain #getDefault} or {@linkplain #getInstance getInstance()}).
* <li>use this TerminalFactory object to access the CardTerminals by
* calling the {@linkplain #terminals} method.
* </ul>
*
* <p>Each TerminalFactory has a <code>type</code> indicating how it
* was implemented. It must be specified when the implementation is obtained
* using a {@linkplain #getInstance getInstance()} method and can be retrieved
* via the {@linkplain #getType} method.
*
* <P>The following standard type names have been defined:
* <dl>
* <dt><code>PC/SC</code>
* <dd>an implementation that calls into the PC/SC Smart Card stack
* of the host platform.
* Implementations do not require parameters and accept "null" as argument
* in the getInstance() calls.
* <dt><code>None</code>
* <dd>an implementation that does not supply any CardTerminals. On platforms
* that do not support other implementations,
* {@linkplain #getDefaultType} returns <code>None</code> and
* {@linkplain #getDefault} returns an instance of a <code>None</code>
* TerminalFactory. Factories of this type cannot be obtained by calling the
* <code>getInstance()</code> methods.
* </dl>
* Additional standard types may be defined in the future.
*
* <p><strong>Note:</strong>
* Provider implementations that accept initialization parameters via the
* <code>getInstance()</code> methods are strongly
* encouraged to use a {@linkplain java.util.Properties} object as the
* representation for String name-value pair based parameters whenever
* possible. This allows applications to more easily interoperate with
* multiple providers than if each provider used different provider
* specific class as parameters.
*
* <P>TerminalFactory utilizes an extensible service provider framework.
* Service providers that wish to add a new implementation should see the
* {@linkplain TerminalFactorySpi} class for more information.
*
* @see CardTerminals
* @see Provider
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public final class TerminalFactory {
private static final String PROP_NAME =
"javax.smartcardio.TerminalFactory.DefaultType";
private static final String defaultType;
private static final TerminalFactory defaultFactory;
static {
// lookup up the user specified type, default to PC/SC
@SuppressWarnings("removal")
String type = AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty(PROP_NAME, "PC/SC")).trim();
TerminalFactory factory = null;
try {
factory = TerminalFactory.getInstance(type, null);
} catch (Exception e) {
// ignore
}
if (factory == null) {
// if that did not work, try the Sun PC/SC factory
try {
type = "PC/SC";
Provider sun = Security.getProvider("SunPCSC");
if (sun == null) {
@SuppressWarnings("deprecation")
Object o = Class.forName("sun.security.smartcardio.SunPCSC").newInstance();
sun = (Provider)o;
}
factory = TerminalFactory.getInstance(type, null, sun);
} catch (Exception e) {
// ignore
}
}
if (factory == null) {
type = "None";
factory = new TerminalFactory
(NoneFactorySpi.INSTANCE, NoneProvider.INSTANCE, "None");
}
defaultType = type;
defaultFactory = factory;
}
private static final class NoneProvider extends Provider {
private static final long serialVersionUID = 2745808869881593918L;
static final Provider INSTANCE = new NoneProvider();
private NoneProvider() {
super("None", "1.0", "none");
}
}
private static final class NoneFactorySpi extends TerminalFactorySpi {
static final TerminalFactorySpi INSTANCE = new NoneFactorySpi();
private NoneFactorySpi() {
// empty
}
protected CardTerminals engineTerminals() {
return NoneCardTerminals.INSTANCE;
}
}
private static final class NoneCardTerminals extends CardTerminals {
static final CardTerminals INSTANCE = new NoneCardTerminals();
private NoneCardTerminals() {
// empty
}
public List<CardTerminal> list(State state) throws CardException {
if (state == null) {
throw new NullPointerException();
}
return Collections.emptyList();
}
public boolean waitForChange(long timeout) throws CardException {
throw new IllegalStateException("no terminals");
}
}
private final TerminalFactorySpi spi;
private final Provider provider;
private final String type;
private TerminalFactory(TerminalFactorySpi spi, Provider provider, String type) {
this.spi = spi;
this.provider = provider;
this.type = type;
}
/**
* Get the default TerminalFactory type.
*
* <p>It is determined as follows:
*
* when this class is initialized, the system property
* {@systemProperty javax.smartcardio.TerminalFactory.DefaultType}
* is examined. If it is set, a TerminalFactory of this type is
* instantiated by calling the {@linkplain #getInstance
* getInstance(String,Object)} method passing
* <code>null</code> as the value for <code>params</code>. If the call
* succeeds, the type becomes the default type and the factory becomes
* the {@linkplain #getDefault default} factory.
*
* <p>If the system property is not set or the getInstance() call fails
* for any reason, the system defaults to an implementation specific
* default type and TerminalFactory.
*
* @return the default TerminalFactory type
*/
public static String getDefaultType() {
return defaultType;
}
/**
* Returns the default TerminalFactory instance. See
* {@linkplain #getDefaultType} for more information.
*
* <p>A default TerminalFactory is always available. However, depending
* on the implementation, it may not offer any terminals.
*
* @return the default TerminalFactory
*/
public static TerminalFactory getDefault() {
return defaultFactory;
}
/**
* Returns a TerminalFactory of the specified type that is initialized
* with the specified parameters.
*
* <p> This method traverses the list of registered security Providers,
* starting with the most preferred Provider.
* A new TerminalFactory object encapsulating the
* TerminalFactorySpi implementation from the first
* Provider that supports the specified type is returned.
*
* <p> Note that the list of registered providers may be retrieved via
* the {@linkplain Security#getProviders() Security.getProviders()} method.
*
* <p>The <code>TerminalFactory</code> is initialized with the
* specified parameters Object. The type of parameters
* needed may vary between different types of <code>TerminalFactory</code>s.
*
* @implNote
* The JDK Reference Implementation additionally uses the
* {@code jdk.security.provider.preferred}
* {@link Security#getProperty(String) Security} property to determine
* the preferred provider order for the specified algorithm. This
* may be different than the order of providers returned by
* {@link Security#getProviders() Security.getProviders()}.
*
* @param type the type of the requested TerminalFactory
* @param params the parameters to pass to the TerminalFactorySpi
* implementation, or null if no parameters are needed
* @return a TerminalFactory of the specified type
*
* @throws NullPointerException if type is null
* @throws NoSuchAlgorithmException if no Provider supports a
* TerminalFactorySpi of the specified type
*/
public static TerminalFactory getInstance(String type, Object params)
throws NoSuchAlgorithmException {
Instance instance = GetInstance.getInstance("TerminalFactory",
TerminalFactorySpi.class, type, params);
return new TerminalFactory((TerminalFactorySpi)instance.impl,
instance.provider, type);
}
/**
* Returns a TerminalFactory of the specified type that is initialized
* with the specified parameters.
*
* <p> A new TerminalFactory object encapsulating the
* TerminalFactorySpi implementation from the specified provider
* is returned. The specified provider must be registered
* in the security provider list.
*
* <p> Note that the list of registered providers may be retrieved via
* the {@linkplain Security#getProviders() Security.getProviders()} method.
*
* <p>The <code>TerminalFactory</code> is initialized with the
* specified parameters Object. The type of parameters
* needed may vary between different types of <code>TerminalFactory</code>s.
*
* @param type the type of the requested TerminalFactory
* @param params the parameters to pass to the TerminalFactorySpi
* implementation, or null if no parameters are needed
* @param provider the name of the provider
* @return a TerminalFactory of the specified type
*
* @throws NullPointerException if type is null
* @throws IllegalArgumentException if provider is null or the empty String
* @throws NoSuchAlgorithmException if a TerminalFactorySpi implementation
* of the specified type is not available from the specified provider
* @throws NoSuchAlgorithmException if no TerminalFactory of the
* specified type could be found
* @throws NoSuchProviderException if the specified provider could not
* be found
*/
public static TerminalFactory getInstance(String type, Object params,
String provider) throws NoSuchAlgorithmException, NoSuchProviderException {
Instance instance = GetInstance.getInstance("TerminalFactory",
TerminalFactorySpi.class, type, params, provider);
return new TerminalFactory((TerminalFactorySpi)instance.impl,
instance.provider, type);
}
/**
* Returns a TerminalFactory of the specified type that is initialized
* with the specified parameters.
*
* <p> A new TerminalFactory object encapsulating the
* TerminalFactorySpi implementation from the specified provider object
* is returned. Note that the specified provider object does not have to be
* registered in the provider list.
*
* <p>The <code>TerminalFactory</code> is initialized with the
* specified parameters Object. The type of parameters
* needed may vary between different types of <code>TerminalFactory</code>s.
*
* @param type the type of the requested TerminalFactory
* @param params the parameters to pass to the TerminalFactorySpi
* implementation, or null if no parameters are needed
* @param provider the provider
* @return a TerminalFactory of the specified type
*
* @throws NullPointerException if type is null
* @throws IllegalArgumentException if provider is null
* @throws NoSuchAlgorithmException if a TerminalFactorySpi implementation
* of the specified type is not available from the specified Provider
*/
public static TerminalFactory getInstance(String type, Object params,
Provider provider) throws NoSuchAlgorithmException {
Instance instance = GetInstance.getInstance("TerminalFactory",
TerminalFactorySpi.class, type, params, provider);
return new TerminalFactory((TerminalFactorySpi)instance.impl,
instance.provider, type);
}
/**
* Returns the provider of this TerminalFactory.
*
* @return the provider of this TerminalFactory.
*/
public Provider getProvider() {
return provider;
}
/**
* Returns the type of this TerminalFactory. This is the value that was
* specified in the getInstance() method that returned this object.
*
* @return the type of this TerminalFactory
*/
public String getType() {
return type;
}
/**
* Returns a new CardTerminals object encapsulating the terminals
* supported by this factory.
* See the class comment of the {@linkplain CardTerminals} class
* regarding how the returned objects can be shared and reused.
*
* @return a new CardTerminals object encapsulating the terminals
* supported by this factory.
*/
public CardTerminals terminals() {
return spi.engineTerminals();
}
/**
* Returns a string representation of this TerminalFactory.
*
* @return a string representation of this TerminalFactory.
*/
public String toString() {
return "TerminalFactory for type " + type + " from provider "
+ provider.getName();
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2005, 2006, 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 javax.smartcardio;
import java.util.*;
/**
* The TerminalFactorySpi class defines the service provider interface.
* Applications do not access this class directly, instead see
* {@linkplain TerminalFactory}.
*
* <P>Service providers that want to write a new implementation should define
* a concrete subclass of TerminalFactorySpi with a constructor that takes
* an <code>Object</code> as parameter. That class needs to be registered
* in a {@linkplain java.security.Provider}. The engine
* {@linkplain java.security.Provider.Service#getType type} is
* <code>TerminalFactory</code>.
* Service providers also need to implement subclasses of the abstract classes
* {@linkplain CardTerminals}, {@linkplain CardTerminal}, {@linkplain Card},
* and {@linkplain CardChannel}.
*
* <p>For example:
* <pre><em>file MyProvider.java:</em>
*
* package com.somedomain.card;
*
* import java.security.Provider;
*
* public class MyProvider extends Provider {
* public MyProvider() {
* super("MyProvider", 1.0d, "Smart Card Example");
* put("TerminalFactory.MyType", "com.somedomain.card.MySpi");
* }
* }
*
*<em>file MySpi.java</em>
*
* package com.somedomain.card;
*
* import javax.smartcardio.*;
*
* public class MySpi extends TerminalFactoySpi {
* public MySpi(Object parameter) {
* // initialize as appropriate
* }
* protected CardTerminals engineTerminals() {
* // add implementation code here
* }
* }
* </pre>
*
* @see TerminalFactory
* @see java.security.Provider
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
public abstract class TerminalFactorySpi {
/**
* Constructs a new TerminalFactorySpi object.
*
* <p>This class is part of the service provider interface and not accessed
* directly by applications. Applications
* should use TerminalFactory objects, which can be obtained by calling
* one of the
* {@linkplain TerminalFactory#getInstance TerminalFactory.getInstance()}
* methods.
*
* <p>Concrete subclasses should define a constructor that takes an
* <code>Object</code> as parameter. It will be invoked when an
* application calls one of the {@linkplain TerminalFactory#getInstance
* TerminalFactory.getInstance()} methods and receives the <code>params</code>
* object specified by the application.
*/
protected TerminalFactorySpi() {
// empty
}
/**
* Returns the CardTerminals created by this factory.
*
* @return the CardTerminals created by this factory.
*/
protected abstract CardTerminals engineTerminals();
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2005, 2020, 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.
*/
/**
* Java&#x2122; Smart Card I/O API.
*
* This specification describes the Java Smart Card I/O API defined by
* <a href="http://jcp.org/en/jsr/detail?id=268">JSR 268</a>.
*
* It defines a Java API for communication with Smart Cards
* using ISO/IEC 7816-4 APDUs. It thereby allows Java applications to interact with
* applications running on the Smart Card, to store and retrieve data
* on the card, etc.
*
* <p>
* The API is defined by classes in the package
* {@code javax.smartcardio}. They can be classified as follows:
*
* <dl>
* <dt>Classes describing the corresponding Smart Card structures
* <dd>
* <a href="ATR.html">ATR</a>,
* <a href="CommandAPDU.html">CommandAPDU</a>,
* <a href="ResponseAPDU.html">ResponseAPDU</a>
*
* <dt>Factory to obtain implementations
* <dd>
* <a href="TerminalFactory.html">TerminalFactory</a>
*
* <dt>Main classes for card and terminal functions
* <dd>
* <a href="CardTerminals.html">CardTerminals</a>,
* <a href="CardTerminal.html">CardTerminal</a>,
* <a href="Card.html">Card</a>,
* <a href="CardChannel.html">CardChannel</a>
*
* <dt>Supporting permission and exception classes
* <dd>
* <a href="CardPermission.html">CardPermission</a>,
* <a href="CardException.html">CardException</a>,
* <a href="CardNotPresentException.html">CardNotPresentException</a>
*
* <dt>Service provider interface, not accessed directly by applications
* <dd>
* <a href="TerminalFactorySpi.html">TerminalFactorySpi</a>
*
* </dl>
*
*
* <h2>API Example</h2>
*
* A simple example of using the API is:
* <pre>
* // show the list of available terminals
* TerminalFactory factory = TerminalFactory.getDefault();
* List&lt;CardTerminal&gt; terminals = factory.terminals().list();
* System.out.println("Terminals: " + terminals);
* // get the first terminal
* CardTerminal terminal = terminals.get(0);
* // establish a connection with the card
* Card card = terminal.connect("T=0");
* System.out.println("card: " + card);
* CardChannel channel = card.getBasicChannel();
* ResponseAPDU r = channel.transmit(new CommandAPDU(c1));
* System.out.println("response: " + toString(r.getBytes()));
* // disconnect
* card.disconnect(false);
* </pre>
*
* @since 1.6
* @author Andreas Sterbenz
* @author JSR 268 Expert Group
*/
package javax.smartcardio;

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2014, 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.
*/
/**
* Defines the Java Smart Card I/O API.
*
* @moduleGraph
* @since 9
*/
module java.smartcardio {
exports javax.smartcardio;
provides java.security.Provider with
sun.security.smartcardio.SunPCSC;
}

View file

@ -0,0 +1,280 @@
/*
* Copyright (c) 2005, 2023, 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 sun.security.smartcardio;
import jdk.internal.util.OperatingSystem;
import javax.smartcardio.*;
import static sun.security.smartcardio.PCSC.*;
/**
* Card implementation.
*
* @since 1.6
* @author Andreas Sterbenz
*/
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 final ATR atr;
// protocol in use, one of SCARD_PROTOCOL_T0 and SCARD_PROTOCOL_T1
final int protocol;
// the basic logical channel (channel 0)
private final ChannelImpl basicChannel;
// state of this card connection
private volatile State state;
// thread holding exclusive access to the card, or null
private volatile Thread exclusiveThread;
CardImpl(TerminalImpl terminal, String protocol) throws PCSCException {
this.terminal = terminal;
int sharingMode = SCARD_SHARE_SHARED;
int connectProtocol;
if (protocol.equals("*")) {
connectProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
} else if (protocol.equalsIgnoreCase("T=0")) {
connectProtocol = SCARD_PROTOCOL_T0;
} else if (protocol.equalsIgnoreCase("T=1")) {
connectProtocol = SCARD_PROTOCOL_T1;
} else if (protocol.equalsIgnoreCase("direct")) {
// testing
// MSDN states that the preferred protocol can be zero, but doesn't
// specify whether other values are allowed.
// pcsc-lite implementation expects the preferred protocol to be non zero.
connectProtocol = OperatingSystem.isWindows() ? 0 : SCARD_PROTOCOL_RAW;
sharingMode = SCARD_SHARE_DIRECT;
} else {
throw new IllegalArgumentException("Unsupported protocol " + protocol);
}
cardId = SCardConnect(terminal.contextId, terminal.name,
sharingMode, connectProtocol);
byte[] status = new byte[2];
byte[] atrBytes = SCardStatus(cardId, status);
atr = new ATR(atrBytes);
this.protocol = status[1] & 0xff;
basicChannel = new ChannelImpl(this, 0);
state = State.OK;
}
void checkState() {
State s = state;
if (s == State.DISCONNECTED) {
throw new IllegalStateException("Card has been disconnected");
} else if (s == State.REMOVED) {
throw new IllegalStateException("Card has been removed");
}
}
boolean isValid() {
if (state != State.OK) {
return false;
}
// ping card via SCardStatus
try {
SCardStatus(cardId, new byte[2]);
return true;
} catch (PCSCException e) {
state = State.REMOVED;
return false;
}
}
private void checkSecurity(String action) {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new CardPermission(terminal.name, action));
}
}
void handleError(PCSCException e) {
if (e.code == SCARD_W_REMOVED_CARD) {
state = State.REMOVED;
}
}
public ATR getATR() {
return atr;
}
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;
}
}
public CardChannel getBasicChannel() {
checkSecurity("getBasicChannel");
checkState();
return basicChannel;
}
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;
}
private static byte[] commandOpenChannel = new byte[] {0, 0x70, 0, 0, 1};
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
("openLogicalChannel() failed, card response: "
+ PCSC.toString(response));
}
return new ChannelImpl(this, response[0]);
} catch (PCSCException e) {
handleError(e);
throw new CardException("openLogicalChannel() failed", e);
}
}
void checkExclusive() throws CardException {
Thread t = exclusiveThread;
if (t == null) {
return;
}
if (t != Thread.currentThread()) {
throw new CardException("Exclusive access established by another Thread");
}
}
public synchronized void beginExclusive() throws CardException {
checkSecurity("exclusive");
checkState();
if (exclusiveThread != null) {
throw new CardException
("Exclusive access has already been assigned to Thread "
+ exclusiveThread.getName());
}
try {
SCardBeginTransaction(cardId);
} catch (PCSCException e) {
handleError(e);
throw new CardException("beginExclusive() failed", e);
}
exclusiveThread = Thread.currentThread();
}
public synchronized void endExclusive() throws CardException {
checkState();
if (exclusiveThread != Thread.currentThread()) {
throw new IllegalStateException
("Exclusive access not assigned to current Thread");
}
try {
SCardEndTransaction(cardId, SCARD_LEAVE_CARD);
} catch (PCSCException e) {
handleError(e);
throw new CardException("endExclusive() failed", e);
} finally {
exclusiveThread = null;
}
}
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);
return r;
} catch (PCSCException e) {
handleError(e);
throw new CardException("transmitControlCommand() failed", e);
}
}
public void disconnect(boolean reset) throws CardException {
if (reset) {
checkSecurity("reset");
}
if (state != State.OK) {
return;
}
checkExclusive();
try {
SCardDisconnect(cardId, (reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD));
} catch (PCSCException e) {
throw new CardException("disconnect() failed", e);
} finally {
state = State.DISCONNECTED;
exclusiveThread = null;
}
}
public String toString() {
return "PC/SC card in " + terminal.name
+ ", protocol " + getProtocol() + ", state " + state;
}
@SuppressWarnings("removal")
protected void finalize() throws Throwable {
try {
if (state == State.OK) {
state = State.DISCONNECTED;
SCardDisconnect(cardId, SCARD_LEAVE_CARD);
}
} finally {
super.finalize();
}
}
}

View file

@ -0,0 +1,299 @@
/*
* Copyright (c) 2005, 2021, 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 sun.security.smartcardio;
import java.nio.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.smartcardio.*;
import static sun.security.smartcardio.PCSC.*;
/**
* CardChannel implementation.
*
* @since 1.6
* @author Andreas Sterbenz
*/
final class ChannelImpl extends CardChannel {
// the card this channel is associated with
private final CardImpl card;
// the channel number, 0 for the basic logical channel
private final int channel;
// whether this channel has been closed. only logical channels can be closed
private volatile boolean isClosed;
ChannelImpl(CardImpl card, int channel) {
this.card = card;
this.channel = channel;
}
void checkClosed() {
card.checkState();
if (isClosed) {
throw new IllegalStateException("Logical channel has been closed");
}
}
public Card getCard() {
return card;
}
public int getChannelNumber() {
checkClosed();
return channel;
}
private static void checkManageChannel(byte[] b) {
if (b.length < 4) {
throw new IllegalArgumentException
("Command APDU must be at least 4 bytes long");
}
if ((b[0] >= 0) && (b[1] == 0x70)) {
throw new IllegalArgumentException
("Manage channel command not allowed, use openLogicalChannel()");
}
}
public ResponseAPDU transmit(CommandAPDU command) throws CardException {
checkClosed();
card.checkExclusive();
byte[] commandBytes = command.getBytes();
byte[] responseBytes = doTransmit(commandBytes);
return new ResponseAPDU(responseBytes);
}
public int transmit(ByteBuffer command, ByteBuffer response) throws CardException {
checkClosed();
card.checkExclusive();
if ((command == null) || (response == null)) {
throw new NullPointerException();
}
if (response.isReadOnly()) {
throw new ReadOnlyBufferException();
}
if (command == response) {
throw new IllegalArgumentException
("command and response must not be the same object");
}
if (response.remaining() < 258) {
throw new IllegalArgumentException
("Insufficient space in response buffer");
}
byte[] commandBytes = new byte[command.remaining()];
command.get(commandBytes);
byte[] responseBytes = doTransmit(commandBytes);
response.put(responseBytes);
return responseBytes.length;
}
private static final boolean t0GetResponse =
getBooleanProperty("sun.security.smartcardio.t0GetResponse", true);
private static final boolean t1GetResponse =
getBooleanProperty("sun.security.smartcardio.t1GetResponse", true);
private static final boolean t1StripLe =
getBooleanProperty("sun.security.smartcardio.t1StripLe", false);
private static boolean getBooleanProperty(String name, boolean def) {
@SuppressWarnings("removal")
String val = AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty(name));
if (val == null) {
return def;
}
if (val.equalsIgnoreCase("true")) {
return true;
} else if (val.equalsIgnoreCase("false")) {
return false;
} else {
throw new IllegalArgumentException
(name + " must be either 'true' or 'false'");
}
}
private byte[] concat(byte[] b1, byte[] b2, int n2) {
int n1 = b1.length;
if ((n1 == 0) && (n2 == b2.length)) {
return b2;
}
byte[] res = new byte[n1 + n2];
System.arraycopy(b1, 0, res, 0, n1);
System.arraycopy(b2, 0, res, n1, n2);
return res;
}
private static final int RESPONSE_ITERATIONS = 256;
private static final byte[] B0 = new byte[0];
private byte[] doTransmit(byte[] command) throws CardException {
// note that we modify the 'command' array in some cases, so it must
// be a copy of the application provided data.
try {
checkManageChannel(command);
setChannel(command);
int n = command.length;
boolean t0 = card.protocol == SCARD_PROTOCOL_T0;
boolean t1 = card.protocol == SCARD_PROTOCOL_T1;
if (t0 && (n >= 7) && (command[4] == 0)) {
throw new CardException
("Extended length forms not supported for T=0");
}
if ((t0 || (t1 && t1StripLe)) && (n >= 7)) {
int lc = command[4] & 0xff;
if (lc != 0) {
if (n == lc + 6) {
n--;
}
} else {
lc = ((command[5] & 0xff) << 8) | (command[6] & 0xff);
if (n == lc + 9) {
n -= 2;
}
}
}
boolean getresponse = (t0 && t0GetResponse) || (t1 && t1GetResponse);
int k = 0;
byte[] result = B0;
while (true) {
if (++k > RESPONSE_ITERATIONS) {
throw new CardException("Number of response iterations" +
" exceeded maximum " + RESPONSE_ITERATIONS);
}
byte[] response = SCardTransmit
(card.cardId, card.protocol, command, 0, n);
int rn = response.length;
if (getresponse && (rn >= 2) && (n >= 1)) {
// see ISO 7816/2005, 5.1.3
if ((rn == 2) && (response[0] == 0x6c)) {
// Resend command using SW2 as short Le field
command[n - 1] = response[1];
continue;
}
if (response[rn - 2] == 0x61) {
// Issue a GET RESPONSE command with the same CLA
// using SW2 as short Le field
if (rn > 2) {
result = concat(result, response, rn - 2);
}
if (command.length < 5) {
byte cla = command[0];
command = new byte[5];
command[0] = cla;
}
command[1] = (byte)0xC0;
command[2] = 0;
command[3] = 0;
command[4] = response[rn - 1];
n = 5;
continue;
}
}
result = concat(result, response, rn);
break;
}
return result;
} catch (PCSCException e) {
card.handleError(e);
throw new CardException(e);
}
}
private static int getSW(byte[] res) throws CardException {
if (res.length < 2) {
throw new CardException("Invalid response length: " + res.length);
}
int sw1 = res[res.length - 2] & 0xff;
int sw2 = res[res.length - 1] & 0xff;
return (sw1 << 8) | sw2;
}
private static boolean isOK(byte[] res) throws CardException {
return (res.length == 2) && (getSW(res) == 0x9000);
}
private void setChannel(byte[] com) {
int cla = com[0];
if (cla < 0) {
// proprietary class format, cannot set or check logical channel
// for now, just return
return;
}
// classes 001x xxxx is reserved for future use in ISO, ignore
if ((cla & 0xe0) == 0x20) {
return;
}
// see ISO 7816/2005, table 2 and 3
if (channel <= 3) {
// mask of bits 7, 1, 0 (channel number)
// 0xbc == 1011 1100
com[0] &= (byte) 0xbc;
com[0] |= (byte) channel;
} else if (channel <= 19) {
// mask of bits 7, 3, 2, 1, 0 (channel number)
// 0xbc == 1011 0000
com[0] &= (byte) 0xb0;
com[0] |= (byte) 0x40;
com[0] |= (byte) (channel - 4);
} else {
throw new RuntimeException("Unsupported channel number: " + channel);
}
}
public void close() throws CardException {
if (getChannelNumber() == 0) {
throw new IllegalStateException("Cannot close basic logical channel");
}
if (isClosed) {
return;
}
card.checkExclusive();
try {
byte[] com = new byte[] {0x00, 0x70, (byte)0x80, 0};
com[3] = (byte)getChannelNumber();
setChannel(com);
byte[] res = SCardTransmit(card.cardId, card.protocol, com, 0, com.length);
if (isOK(res) == false) {
throw new CardException("close() failed: " + PCSC.toString(res));
}
} catch (PCSCException e) {
card.handleError(e);
throw new CardException("Could not close channel", e);
} finally {
isClosed = true;
}
}
public String toString() {
return "PC/SC channel " + channel;
}
}

View file

@ -0,0 +1,187 @@
/*
* Copyright (c) 2005, 2021, 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 sun.security.smartcardio;
import java.security.AccessController;
/**
* Access to native PC/SC functions and definition of PC/SC constants.
* Initialization and platform specific PC/SC constants are handled in
* the platform specific superclass.
*
* @since 1.6
* @author Andreas Sterbenz
*/
final class PCSC extends PlatformPCSC {
private PCSC() {
// no instantiation
}
static void checkAvailable() throws RuntimeException {
if (initException != null) {
throw new UnsupportedOperationException
("PC/SC not available on this platform", initException);
}
}
// returns SCARDCONTEXT (contextId)
static native long SCardEstablishContext
(int scope)
throws PCSCException;
static native String[] SCardListReaders
(long contextId)
throws PCSCException;
// returns SCARDHANDLE (cardId)
static native long SCardConnect
(long contextId, String readerName, int shareMode, int preferredProtocols)
throws PCSCException;
static native byte[] SCardTransmit
(long cardId, int protocol, byte[] buf, int ofs, int len)
throws PCSCException;
// returns the ATR of the card, updates status[] with reader state and protocol
static native byte[] SCardStatus
(long cardId, byte[] status)
throws PCSCException;
static native void SCardDisconnect
(long cardId, int disposition)
throws PCSCException;
// returns dwEventState[] of the same size and order as readerNames[]
static native int[] SCardGetStatusChange
(long contextId, long timeout, int[] currentState, String[] readerNames)
throws PCSCException;
static native void SCardBeginTransaction
(long cardId)
throws PCSCException;
static native void SCardEndTransaction
(long cardId, int disposition)
throws PCSCException;
static native byte[] SCardControl
(long cardId, int controlCode, byte[] sendBuffer)
throws PCSCException;
// PCSC success/error/failure/warning codes
static final int SCARD_S_SUCCESS = 0x00000000;
static final int SCARD_E_CANCELLED = 0x80100002;
static final int SCARD_E_CANT_DISPOSE = 0x8010000E;
static final int SCARD_E_INSUFFICIENT_BUFFER = 0x80100008;
static final int SCARD_E_INVALID_ATR = 0x80100015;
static final int SCARD_E_INVALID_HANDLE = 0x80100003;
static final int SCARD_E_INVALID_PARAMETER = 0x80100004;
static final int SCARD_E_INVALID_TARGET = 0x80100005;
static final int SCARD_E_INVALID_VALUE = 0x80100011;
static final int SCARD_E_NO_MEMORY = 0x80100006;
static final int SCARD_F_COMM_ERROR = 0x80100013;
static final int SCARD_F_INTERNAL_ERROR = 0x80100001;
static final int SCARD_F_UNKNOWN_ERROR = 0x80100014;
static final int SCARD_F_WAITED_TOO_LONG = 0x80100007;
static final int SCARD_E_UNKNOWN_READER = 0x80100009;
static final int SCARD_E_TIMEOUT = 0x8010000A;
static final int SCARD_E_SHARING_VIOLATION = 0x8010000B;
static final int SCARD_E_NO_SMARTCARD = 0x8010000C;
static final int SCARD_E_UNKNOWN_CARD = 0x8010000D;
static final int SCARD_E_PROTO_MISMATCH = 0x8010000F;
static final int SCARD_E_NOT_READY = 0x80100010;
static final int SCARD_E_SYSTEM_CANCELLED = 0x80100012;
static final int SCARD_E_NOT_TRANSACTED = 0x80100016;
static final int SCARD_E_READER_UNAVAILABLE = 0x80100017;
static final int SCARD_W_UNSUPPORTED_CARD = 0x80100065;
static final int SCARD_W_UNRESPONSIVE_CARD = 0x80100066;
static final int SCARD_W_UNPOWERED_CARD = 0x80100067;
static final int SCARD_W_RESET_CARD = 0x80100068;
static final int SCARD_W_REMOVED_CARD = 0x80100069;
static final int SCARD_W_INSERTED_CARD = 0x8010006A;
static final int SCARD_E_UNSUPPORTED_FEATURE = 0x8010001F;
static final int SCARD_E_PCI_TOO_SMALL = 0x80100019;
static final int SCARD_E_READER_UNSUPPORTED = 0x8010001A;
static final int SCARD_E_DUPLICATE_READER = 0x8010001B;
static final int SCARD_E_CARD_UNSUPPORTED = 0x8010001C;
static final int SCARD_E_NO_SERVICE = 0x8010001D;
static final int SCARD_E_SERVICE_STOPPED = 0x8010001E;
// MS undocumented
static final int SCARD_E_NO_READERS_AVAILABLE = 0x8010002E;
// std. Windows invalid handle return code, used instead of SCARD code
static final int WINDOWS_ERROR_INVALID_HANDLE = 6;
static final int WINDOWS_ERROR_INVALID_PARAMETER = 87;
//
static final int SCARD_SCOPE_USER = 0x0000;
static final int SCARD_SCOPE_TERMINAL = 0x0001;
static final int SCARD_SCOPE_SYSTEM = 0x0002;
static final int SCARD_SCOPE_GLOBAL = 0x0003;
static final int SCARD_SHARE_EXCLUSIVE = 0x0001;
static final int SCARD_SHARE_SHARED = 0x0002;
static final int SCARD_SHARE_DIRECT = 0x0003;
static final int SCARD_LEAVE_CARD = 0x0000;
static final int SCARD_RESET_CARD = 0x0001;
static final int SCARD_UNPOWER_CARD = 0x0002;
static final int SCARD_EJECT_CARD = 0x0003;
static final int SCARD_STATE_UNAWARE = 0x0000;
static final int SCARD_STATE_IGNORE = 0x0001;
static final int SCARD_STATE_CHANGED = 0x0002;
static final int SCARD_STATE_UNKNOWN = 0x0004;
static final int SCARD_STATE_UNAVAILABLE = 0x0008;
static final int SCARD_STATE_EMPTY = 0x0010;
static final int SCARD_STATE_PRESENT = 0x0020;
static final int SCARD_STATE_ATRMATCH = 0x0040;
static final int SCARD_STATE_EXCLUSIVE = 0x0080;
static final int SCARD_STATE_INUSE = 0x0100;
static final int SCARD_STATE_MUTE = 0x0200;
static final int SCARD_STATE_UNPOWERED = 0x0400;
static final int TIMEOUT_INFINITE = 0xffffffff;
private static final char[] hexDigits = "0123456789abcdef".toCharArray();
public static String toString(byte[] b) {
StringBuilder sb = new StringBuilder(b.length * 3);
for (int i = 0; i < b.length; i++) {
int k = b[i] & 0xff;
if (i != 0) {
sb.append(':');
}
sb.append(hexDigits[k >>> 4]);
sb.append(hexDigits[k & 0xf]);
}
return sb.toString();
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2005, 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 sun.security.smartcardio;
import static sun.security.smartcardio.PCSC.*;
/**
* Exception for PC/SC errors. The native code portion checks the return value
* of the SCard* functions. If it indicates an error, the native code constructs
* an instance of this exception, throws it, and returns to Java.
*
* @since 1.6
* @author Andreas Sterbenz
*/
final class PCSCException extends Exception {
private static final long serialVersionUID = 4181137171979130432L;
final int code;
PCSCException(int code) {
super(toErrorString(code));
this.code = code;
}
private static String toErrorString(int code) {
switch (code) {
case SCARD_S_SUCCESS : return "SCARD_S_SUCCESS";
case SCARD_E_CANCELLED : return "SCARD_E_CANCELLED";
case SCARD_E_CANT_DISPOSE : return "SCARD_E_CANT_DISPOSE";
case SCARD_E_INSUFFICIENT_BUFFER : return "SCARD_E_INSUFFICIENT_BUFFER";
case SCARD_E_INVALID_ATR : return "SCARD_E_INVALID_ATR";
case SCARD_E_INVALID_HANDLE : return "SCARD_E_INVALID_HANDLE";
case SCARD_E_INVALID_PARAMETER : return "SCARD_E_INVALID_PARAMETER";
case SCARD_E_INVALID_TARGET : return "SCARD_E_INVALID_TARGET";
case SCARD_E_INVALID_VALUE : return "SCARD_E_INVALID_VALUE";
case SCARD_E_NO_MEMORY : return "SCARD_E_NO_MEMORY";
case SCARD_F_COMM_ERROR : return "SCARD_F_COMM_ERROR";
case SCARD_F_INTERNAL_ERROR : return "SCARD_F_INTERNAL_ERROR";
case SCARD_F_UNKNOWN_ERROR : return "SCARD_F_UNKNOWN_ERROR";
case SCARD_F_WAITED_TOO_LONG : return "SCARD_F_WAITED_TOO_LONG";
case SCARD_E_UNKNOWN_READER : return "SCARD_E_UNKNOWN_READER";
case SCARD_E_TIMEOUT : return "SCARD_E_TIMEOUT";
case SCARD_E_SHARING_VIOLATION : return "SCARD_E_SHARING_VIOLATION";
case SCARD_E_NO_SMARTCARD : return "SCARD_E_NO_SMARTCARD";
case SCARD_E_UNKNOWN_CARD : return "SCARD_E_UNKNOWN_CARD";
case SCARD_E_PROTO_MISMATCH : return "SCARD_E_PROTO_MISMATCH";
case SCARD_E_NOT_READY : return "SCARD_E_NOT_READY";
case SCARD_E_SYSTEM_CANCELLED : return "SCARD_E_SYSTEM_CANCELLED";
case SCARD_E_NOT_TRANSACTED : return "SCARD_E_NOT_TRANSACTED";
case SCARD_E_READER_UNAVAILABLE : return "SCARD_E_READER_UNAVAILABLE";
case SCARD_W_UNSUPPORTED_CARD : return "SCARD_W_UNSUPPORTED_CARD";
case SCARD_W_UNRESPONSIVE_CARD : return "SCARD_W_UNRESPONSIVE_CARD";
case SCARD_W_UNPOWERED_CARD : return "SCARD_W_UNPOWERED_CARD";
case SCARD_W_RESET_CARD : return "SCARD_W_RESET_CARD";
case SCARD_W_REMOVED_CARD : return "SCARD_W_REMOVED_CARD";
case SCARD_W_INSERTED_CARD : return "SCARD_W_INSERTED_CARD";
case SCARD_E_UNSUPPORTED_FEATURE : return "SCARD_E_UNSUPPORTED_FEATURE";
case SCARD_E_PCI_TOO_SMALL : return "SCARD_E_PCI_TOO_SMALL";
case SCARD_E_READER_UNSUPPORTED : return "SCARD_E_READER_UNSUPPORTED";
case SCARD_E_DUPLICATE_READER : return "SCARD_E_DUPLICATE_READER";
case SCARD_E_CARD_UNSUPPORTED : return "SCARD_E_CARD_UNSUPPORTED";
case SCARD_E_NO_SERVICE : return "SCARD_E_NO_SERVICE";
case SCARD_E_SERVICE_STOPPED : return "SCARD_E_SERVICE_STOPPED";
case SCARD_E_NO_READERS_AVAILABLE: return "SCARD_E_NO_READERS_AVAILABLE";
case WINDOWS_ERROR_INVALID_HANDLE: return "WINDOWS_ERROR_INVALID_HANDLE";
case WINDOWS_ERROR_INVALID_PARAMETER: return "WINDOWS_ERROR_INVALID_PARAMETER";
default: return "Unknown error 0x" + Integer.toHexString(code);
}
}
}

View file

@ -0,0 +1,267 @@
/*
* Copyright (c) 2005, 2006, 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 sun.security.smartcardio;
import java.util.*;
import java.lang.ref.*;
import javax.smartcardio.*;
import static javax.smartcardio.CardTerminals.State.*;
import static sun.security.smartcardio.PCSC.*;
/**
* TerminalFactorySpi implementation class.
*
* @since 1.6
* @author Andreas Sterbenz
*/
final class PCSCTerminals extends CardTerminals {
// SCARDCONTEXT, currently shared between all threads/terminals
private static long contextId;
// terminal state used by waitForCard()
private Map<String,ReaderState> stateMap;
PCSCTerminals() {
// empty
}
static synchronized void initContext() throws PCSCException {
if (contextId == 0) {
contextId = SCardEstablishContext(SCARD_SCOPE_USER);
}
}
private static final Map<String,Reference<TerminalImpl>> terminals
= new HashMap<String,Reference<TerminalImpl>>();
private static synchronized TerminalImpl implGetTerminal(String name) {
Reference<TerminalImpl> ref = terminals.get(name);
TerminalImpl terminal = (ref != null) ? ref.get() : null;
if (terminal != null) {
return terminal;
}
terminal = new TerminalImpl(contextId, name);
terminals.put(name, new WeakReference<TerminalImpl>(terminal));
return terminal;
}
public synchronized List<CardTerminal> list(State state) throws CardException {
if (state == null) {
throw new NullPointerException();
}
try {
String[] readerNames = SCardListReaders(contextId);
List<CardTerminal> list = new ArrayList<CardTerminal>(readerNames.length);
if (stateMap == null) {
// If waitForChange() has never been called, treat event
// queries as status queries.
if (state == CARD_INSERTION) {
state = CARD_PRESENT;
} else if (state == CARD_REMOVAL) {
state = CARD_ABSENT;
}
}
for (String readerName : readerNames) {
CardTerminal terminal = implGetTerminal(readerName);
ReaderState readerState;
switch (state) {
case ALL:
list.add(terminal);
break;
case CARD_PRESENT:
if (terminal.isCardPresent()) {
list.add(terminal);
}
break;
case CARD_ABSENT:
if (terminal.isCardPresent() == false) {
list.add(terminal);
}
break;
case CARD_INSERTION:
readerState = stateMap.get(readerName);
if ((readerState != null) && readerState.isInsertion()) {
list.add(terminal);
}
break;
case CARD_REMOVAL:
readerState = stateMap.get(readerName);
if ((readerState != null) && readerState.isRemoval()) {
list.add(terminal);
}
break;
default:
throw new CardException("Unknown state: " + state);
}
}
return Collections.unmodifiableList(list);
} catch (PCSCException e) {
throw new CardException("list() failed", e);
}
}
private static class ReaderState {
private int current, previous;
ReaderState() {
current = SCARD_STATE_UNAWARE;
previous = SCARD_STATE_UNAWARE;
}
int get() {
return current;
}
void update(int newState) {
previous = current;
current = newState;
}
boolean isInsertion() {
return !present(previous) && present(current);
}
boolean isRemoval() {
return present(previous) && !present(current);
}
static boolean present(int state) {
return (state & SCARD_STATE_PRESENT) != 0;
}
}
public synchronized boolean waitForChange(long timeout) throws CardException {
if (timeout < 0) {
throw new IllegalArgumentException
("Timeout must not be negative: " + timeout);
}
if (stateMap == null) {
// We need to initialize the state database.
// Do that with a recursive call, which will return immediately
// because we pass SCARD_STATE_UNAWARE.
// After that, proceed with the real call.
stateMap = new HashMap<String,ReaderState>();
waitForChange(0);
}
if (timeout == 0) {
timeout = TIMEOUT_INFINITE;
}
try {
String[] readerNames = SCardListReaders(contextId);
int n = readerNames.length;
if (n == 0) {
throw new IllegalStateException("No terminals available");
}
int[] status = new int[n];
ReaderState[] readerStates = new ReaderState[n];
for (int i = 0; i < readerNames.length; i++) {
String name = readerNames[i];
ReaderState state = stateMap.get(name);
if (state == null) {
state = new ReaderState();
}
readerStates[i] = state;
status[i] = state.get();
}
status = SCardGetStatusChange(contextId, timeout, status, readerNames);
stateMap.clear(); // remove any readers that are no longer available
for (int i = 0; i < n; i++) {
ReaderState state = readerStates[i];
state.update(status[i]);
stateMap.put(readerNames[i], state);
}
return true;
} catch (PCSCException e) {
if (e.code == SCARD_E_TIMEOUT) {
return false;
} else {
throw new CardException("waitForChange() failed", e);
}
}
}
static List<CardTerminal> waitForCards(List<? extends CardTerminal> terminals,
long timeout, boolean wantPresent) throws CardException {
// the argument sanity checks are performed in
// javax.smartcardio.TerminalFactory or TerminalImpl
long thisTimeout;
if (timeout == 0) {
timeout = TIMEOUT_INFINITE;
thisTimeout = TIMEOUT_INFINITE;
} else {
// if timeout is not infinite, do the initial call that retrieves
// the status with a 0 timeout. Otherwise, we might get incorrect
// timeout exceptions (seen on Solaris with PC/SC shim)
thisTimeout = 0;
}
String[] names = new String[terminals.size()];
int i = 0;
for (CardTerminal terminal : terminals) {
if (terminal instanceof TerminalImpl == false) {
throw new IllegalArgumentException
("Invalid terminal type: " + terminal.getClass().getName());
}
TerminalImpl impl = (TerminalImpl)terminal;
names[i++] = impl.name;
}
int[] status = new int[names.length];
Arrays.fill(status, SCARD_STATE_UNAWARE);
try {
while (true) {
// note that we pass "timeout" on each native PC/SC call
// that means that if we end up making multiple (more than 2)
// calls, we might wait too long.
// for now assume that is unlikely and not a problem.
status = SCardGetStatusChange(contextId, thisTimeout, status, names);
thisTimeout = timeout;
List<CardTerminal> results = null;
for (i = 0; i < names.length; i++) {
boolean nowPresent = (status[i] & SCARD_STATE_PRESENT) != 0;
if (nowPresent == wantPresent) {
if (results == null) {
results = new ArrayList<CardTerminal>();
}
results.add(implGetTerminal(names[i]));
}
}
if (results != null) {
return Collections.unmodifiableList(results);
}
}
} catch (PCSCException e) {
if (e.code == SCARD_E_TIMEOUT) {
return Collections.emptyList();
} else {
throw new CardException("waitForCard() failed", e);
}
}
}
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2005, 2021, 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 sun.security.smartcardio;
import java.security.*;
import javax.smartcardio.*;
import static sun.security.util.SecurityConstants.PROVIDER_VER;
/**
* Provider object for PC/SC.
*
* @since 1.6
* @author Andreas Sterbenz
*/
public final class SunPCSC extends Provider {
private static final long serialVersionUID = 6168388284028876579L;
private static final class ProviderService extends Provider.Service {
ProviderService(Provider p, String type, String algo, String cn) {
super(p, type, algo, cn, null, null);
}
@Override
public Object newInstance(Object ctrParamObj)
throws NoSuchAlgorithmException {
String type = getType();
String algo = getAlgorithm();
try {
if (type.equals("TerminalFactory") &&
algo.equals("PC/SC")) {
return new SunPCSC.Factory(ctrParamObj);
}
} catch (Exception ex) {
throw new NoSuchAlgorithmException("Error constructing " +
type + " for " + algo + " using SunPCSC", ex);
}
throw new ProviderException("No impl for " + algo +
" " + type);
}
}
@SuppressWarnings("removal")
public SunPCSC() {
super("SunPCSC", PROVIDER_VER, "Sun PC/SC provider");
final Provider p = this;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
putService(new ProviderService(p, "TerminalFactory",
"PC/SC", "sun.security.smartcardio.SunPCSC$Factory"));
return null;
}
});
}
public static final class Factory extends TerminalFactorySpi {
public Factory(Object obj) throws PCSCException {
if (obj != null) {
throw new IllegalArgumentException
("SunPCSC factory does not use parameters");
}
// make sure PCSC is available and that we can obtain a context
PCSC.checkAvailable();
PCSCTerminals.initContext();
}
/**
* Returns the available readers.
* This must be a new object for each call.
*/
protected CardTerminals engineTerminals() {
return new PCSCTerminals();
}
}
}

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2005, 2021, 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 sun.security.smartcardio;
import java.util.*;
import javax.smartcardio.*;
import static sun.security.smartcardio.PCSC.*;
/**
* CardTerminal implementation.
*
* @since 1.6
* @author Andreas Sterbenz
*/
final class TerminalImpl extends CardTerminal {
// native SCARDCONTEXT
final long contextId;
// the name of this terminal (native PC/SC name)
final String name;
private CardImpl card;
TerminalImpl(long contextId, String name) {
this.contextId = contextId;
this.name = name;
}
public String getName() {
return name;
}
public synchronized Card connect(String protocol) throws CardException {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new CardPermission(name, "connect"));
}
if (card != null) {
if (card.isValid()) {
String cardProto = card.getProtocol();
if (protocol.equals("*") || protocol.equalsIgnoreCase(cardProto)) {
return card;
} else {
throw new CardException("Cannot connect using " + protocol
+ ", connection already established using " + cardProto);
}
} else {
card = null;
}
}
try {
card = new CardImpl(this, protocol);
return card;
} catch (PCSCException e) {
if (e.code == SCARD_W_REMOVED_CARD || e.code == SCARD_E_NO_SMARTCARD) {
throw new CardNotPresentException("No card present", e);
} else {
throw new CardException("connect() failed", e);
}
}
}
public boolean isCardPresent() throws CardException {
try {
int[] status = SCardGetStatusChange(contextId, 0,
new int[] {SCARD_STATE_UNAWARE}, new String[] {name});
return (status[0] & SCARD_STATE_PRESENT) != 0;
} catch (PCSCException e) {
throw new CardException("isCardPresent() failed", e);
}
}
private boolean waitForCard(boolean wantPresent, long timeout) throws CardException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout must not be negative");
}
if (timeout == 0) {
timeout = TIMEOUT_INFINITE;
}
int[] status = new int[] {SCARD_STATE_UNAWARE};
String[] readers = new String[] {name};
try {
// check if card status already matches
status = SCardGetStatusChange(contextId, 0, status, readers);
boolean present = (status[0] & SCARD_STATE_PRESENT) != 0;
if (wantPresent == present) {
return true;
}
// no match, wait (until timeout expires)
long end = System.currentTimeMillis() + timeout;
while (wantPresent != present && timeout != 0) {
// set remaining timeout
if (timeout != TIMEOUT_INFINITE) {
timeout = Math.max(end - System.currentTimeMillis(), 0l);
}
status = SCardGetStatusChange(contextId, timeout, status, readers);
present = (status[0] & SCARD_STATE_PRESENT) != 0;
}
return wantPresent == present;
} catch (PCSCException e) {
if (e.code == SCARD_E_TIMEOUT) {
return false;
} else {
throw new CardException("waitForCard() failed", e);
}
}
}
public boolean waitForCardPresent(long timeout) throws CardException {
return waitForCard(true, timeout);
}
public boolean waitForCardAbsent(long timeout) throws CardException {
return waitForCard(false, timeout);
}
public String toString() {
return "PC/SC terminal " + name;
}
}

View file

@ -0,0 +1,488 @@
/*
* Copyright (c) 2005, 2024, 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.
*/
/* disable asserts in product mode */
#ifndef DEBUG
#ifndef NDEBUG
#define NDEBUG
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <winscard.h>
// #define J2PCSC_DEBUG
#ifdef J2PCSC_DEBUG
#define debug_printf(format, ...) printf(format, ##__VA_ARGS__)
#else
#define debug_printf(format, ...)
#endif
#include "sun_security_smartcardio_PCSC.h"
#include "pcsc_md.h"
#include "jni_util.h"
#define MAX_STACK_BUFFER_SIZE 8192
// make the buffers larger than what should be necessary, just in case
#define ATR_BUFFER_SIZE 128
#define READERNAME_BUFFER_SIZE 128
#define RECEIVE_BUFFER_SIZE MAX_STACK_BUFFER_SIZE
#define J2PCSC_EXCEPTION_NAME "sun/security/smartcardio/PCSCException"
static void throwOutOfMemoryError(JNIEnv *env, const char *msg) {
jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (cls != NULL) /* Otherwise an exception has already been thrown */
(*env)->ThrowNew(env, cls, msg);
}
void throwPCSCException(JNIEnv* env, LONG code) {
jclass pcscClass;
jmethodID constructor;
jthrowable pcscException;
pcscClass = (*env)->FindClass(env, J2PCSC_EXCEPTION_NAME);
if (pcscClass == NULL) {
return;
}
constructor = (*env)->GetMethodID(env, pcscClass, "<init>", "(I)V");
if (constructor == NULL) {
return;
}
pcscException = (jthrowable) (*env)->NewObject(env, pcscClass,
constructor, (jint)code);
if (pcscException != NULL) {
(*env)->Throw(env, pcscException);
}
}
jboolean handleRV(JNIEnv* env, LONG code) {
if (code == SCARD_S_SUCCESS) {
return JNI_FALSE;
} else {
throwPCSCException(env, code);
return JNI_TRUE;
}
}
JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_VERSION_1_4;
}
JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardEstablishContext
(JNIEnv *env, jclass thisClass, jint dwScope)
{
SCARDCONTEXT context = 0;
LONG rv;
debug_printf("-establishContext\n");
rv = CALL_SCardEstablishContext(dwScope, NULL, NULL, &context);
if (handleRV(env, rv)) {
return 0;
}
// note: SCARDCONTEXT is typedef'd as long, so this works
return (jlong)context;
}
/**
* Convert a multi string to a java string array,
*/
jobjectArray pcsc_multi2jstring(JNIEnv *env, char *spec) {
jobjectArray result;
jclass stringClass;
char *cp, **tab = NULL;
jstring js;
int cnt = 0;
cp = spec;
while (*cp != 0) {
cp += (strlen(cp) + 1);
++cnt;
}
tab = (char **)malloc(cnt * sizeof(char *));
if (tab == NULL) {
throwOutOfMemoryError(env, NULL);
return NULL;
}
cnt = 0;
cp = spec;
while (*cp != 0) {
tab[cnt++] = cp;
cp += (strlen(cp) + 1);
}
stringClass = (*env)->FindClass(env, "java/lang/String");
if (stringClass == NULL) {
free(tab);
return NULL;
}
result = (*env)->NewObjectArray(env, cnt, stringClass, NULL);
if (result != NULL) {
while (cnt-- > 0) {
js = (*env)->NewStringUTF(env, tab[cnt]);
if ((*env)->ExceptionCheck(env)) {
free(tab);
return NULL;
}
(*env)->SetObjectArrayElement(env, result, cnt, js);
if ((*env)->ExceptionCheck(env)) {
free(tab);
return NULL;
}
(*env)->DeleteLocalRef(env, js);
}
}
free(tab);
return result;
}
JNIEXPORT jobjectArray JNICALL Java_sun_security_smartcardio_PCSC_SCardListReaders
(JNIEnv *env, jclass thisClass, jlong jContext)
{
SCARDCONTEXT context = (SCARDCONTEXT)jContext;
LONG rv;
LPSTR mszReaders = NULL;
DWORD size = 0;
jobjectArray result;
debug_printf("-context: %x\n", context);
rv = CALL_SCardListReaders(context, NULL, NULL, &size);
if (handleRV(env, rv)) {
return NULL;
}
debug_printf("-size: %d\n", size);
if (size != 0) {
mszReaders = malloc(size);
if (mszReaders == NULL) {
throwOutOfMemoryError(env, NULL);
return NULL;
}
rv = CALL_SCardListReaders(context, NULL, mszReaders, &size);
if (handleRV(env, rv)) {
free(mszReaders);
return NULL;
}
debug_printf("-String: %s\n", mszReaders);
} else {
return NULL;
}
result = pcsc_multi2jstring(env, mszReaders);
free(mszReaders);
return result;
}
JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardConnect
(JNIEnv *env, jclass thisClass, jlong jContext, jstring jReaderName,
jint jShareMode, jint jPreferredProtocols)
{
SCARDCONTEXT context = (SCARDCONTEXT)jContext;
LONG rv;
LPCSTR readerName;
SCARDHANDLE card = 0;
DWORD proto = 0;
readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL);
if (readerName == NULL) {
return 0;
}
rv = CALL_SCardConnect(context, readerName, jShareMode, jPreferredProtocols, &card, &proto);
(*env)->ReleaseStringUTFChars(env, jReaderName, readerName);
debug_printf("-cardhandle: %x\n", card);
debug_printf("-protocol: %d\n", proto);
if (handleRV(env, rv)) {
return 0;
}
return (jlong)card;
}
JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardTransmit
(JNIEnv *env, jclass thisClass, jlong jCard, jint protocol,
jbyteArray jBuf, jint jOfs, jint jLen)
{
SCARDHANDLE card = (SCARDHANDLE)jCard;
LONG rv;
SCARD_IO_REQUEST sendPci;
unsigned char *sbuf;
unsigned char rbuf[RECEIVE_BUFFER_SIZE];
DWORD rlen = RECEIVE_BUFFER_SIZE;
int ofs = (int)jOfs;
int len = (int)jLen;
jbyteArray jOut;
sendPci.dwProtocol = protocol;
sendPci.cbPciLength = sizeof(SCARD_IO_REQUEST);
sbuf = (unsigned char *) ((*env)->GetByteArrayElements(env, jBuf, NULL));
if (sbuf == NULL) {
return NULL;
}
rv = CALL_SCardTransmit(card, &sendPci, sbuf + ofs, len, NULL, rbuf, &rlen);
(*env)->ReleaseByteArrayElements(env, jBuf, (jbyte *)sbuf, JNI_ABORT);
if (handleRV(env, rv)) {
return NULL;
}
jOut = (*env)->NewByteArray(env, rlen);
if (jOut != NULL) {
(*env)->SetByteArrayRegion(env, jOut, 0, rlen, (jbyte *)rbuf);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
}
return jOut;
}
JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardStatus
(JNIEnv *env, jclass thisClass, jlong jCard, jbyteArray jStatus)
{
SCARDHANDLE card = (SCARDHANDLE)jCard;
LONG rv;
char readerName[READERNAME_BUFFER_SIZE];
DWORD readerLen = READERNAME_BUFFER_SIZE;
unsigned char atr[ATR_BUFFER_SIZE];
DWORD atrLen = ATR_BUFFER_SIZE;
DWORD state = 0;
DWORD protocol = 0;
jbyteArray jArray;
jbyte status[2];
rv = CALL_SCardStatus(card, readerName, &readerLen, &state, &protocol, atr, &atrLen);
if (handleRV(env, rv)) {
return NULL;
}
debug_printf("-reader: %s\n", readerName);
debug_printf("-status: %d\n", state);
debug_printf("-protocol: %d\n", protocol);
jArray = (*env)->NewByteArray(env, atrLen);
if (jArray == NULL) {
return NULL;
}
(*env)->SetByteArrayRegion(env, jArray, 0, atrLen, (jbyte *)atr);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
status[0] = (jbyte) state;
status[1] = (jbyte) protocol;
(*env)->SetByteArrayRegion(env, jStatus, 0, 2, status);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
return jArray;
}
JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardDisconnect
(JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition)
{
SCARDHANDLE card = (SCARDHANDLE)jCard;
LONG rv;
rv = CALL_SCardDisconnect(card, jDisposition);
debug_printf("-disconnect: 0x%X\n", rv);
handleRV(env, rv);
return;
}
JNIEXPORT jintArray JNICALL Java_sun_security_smartcardio_PCSC_SCardGetStatusChange
(JNIEnv *env, jclass thisClass, jlong jContext, jlong jTimeout,
jintArray jCurrentState, jobjectArray jReaderNames)
{
SCARDCONTEXT context = (SCARDCONTEXT)jContext;
LONG rv;
int readers = (*env)->GetArrayLength(env, jReaderNames);
SCARD_READERSTATE *readerState;
int i;
jintArray jEventState = NULL;
int *currentState = NULL;
const char *readerName;
readerState = calloc(readers, sizeof(SCARD_READERSTATE));
if (readerState == NULL && readers > 0) {
throwOutOfMemoryError(env, NULL);
return NULL;
}
currentState = (*env)->GetIntArrayElements(env, jCurrentState, NULL);
if (currentState == NULL) {
free(readerState);
return NULL;
}
for (i = 0; i < readers; i++) {
readerState[i].szReader = NULL;
}
for (i = 0; i < readers; i++) {
jobject jReaderName = (*env)->GetObjectArrayElement(env, jReaderNames, i);
if ((*env)->ExceptionCheck(env)) {
goto cleanup;
}
readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL);
if (readerName == NULL) {
goto cleanup;
}
readerState[i].szReader = strdup(readerName);
(*env)->ReleaseStringUTFChars(env, jReaderName, readerName);
if (readerState[i].szReader == NULL) {
throwOutOfMemoryError(env, NULL);
goto cleanup;
}
readerState[i].pvUserData = NULL;
readerState[i].dwCurrentState = currentState[i];
readerState[i].dwEventState = SCARD_STATE_UNAWARE;
readerState[i].cbAtr = 0;
(*env)->DeleteLocalRef(env, jReaderName);
}
if (readers > 0) {
rv = CALL_SCardGetStatusChange(context, (DWORD)jTimeout, readerState, readers);
if (handleRV(env, rv)) {
goto cleanup;
}
}
jEventState = (*env)->NewIntArray(env, readers);
if (jEventState == NULL) {
goto cleanup;
}
for (i = 0; i < readers; i++) {
jint eventStateTmp;
debug_printf("-reader status %s: 0x%X, 0x%X\n", readerState[i].szReader,
readerState[i].dwCurrentState, readerState[i].dwEventState);
eventStateTmp = (jint)readerState[i].dwEventState;
(*env)->SetIntArrayRegion(env, jEventState, i, 1, &eventStateTmp);
if ((*env)->ExceptionCheck(env)) {
jEventState = NULL;
goto cleanup;
}
}
cleanup:
(*env)->ReleaseIntArrayElements(env, jCurrentState, currentState, JNI_ABORT);
for (i = 0; i < readers; i++) {
free((char *)readerState[i].szReader);
}
free(readerState);
return jEventState;
}
JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardBeginTransaction
(JNIEnv *env, jclass thisClass, jlong jCard)
{
SCARDHANDLE card = (SCARDHANDLE)jCard;
LONG rv;
rv = CALL_SCardBeginTransaction(card);
debug_printf("-beginTransaction: 0x%X\n", rv);
handleRV(env, rv);
return;
}
JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardEndTransaction
(JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition)
{
SCARDHANDLE card = (SCARDHANDLE)jCard;
LONG rv;
rv = CALL_SCardEndTransaction(card, jDisposition);
debug_printf("-endTransaction: 0x%X\n", rv);
handleRV(env, rv);
return;
}
JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardControl
(JNIEnv *env, jclass thisClass, jlong jCard, jint jControlCode, jbyteArray jSendBuffer)
{
SCARDHANDLE card = (SCARDHANDLE)jCard;
LONG rv;
jbyte* sendBuffer;
jint sendBufferLength = (*env)->GetArrayLength(env, jSendBuffer);
jbyte receiveBuffer[MAX_STACK_BUFFER_SIZE];
jint receiveBufferLength = MAX_STACK_BUFFER_SIZE;
ULONG returnedLength = 0;
jbyteArray jReceiveBuffer;
sendBuffer = (*env)->GetByteArrayElements(env, jSendBuffer, NULL);
if (sendBuffer == NULL) {
return NULL;
}
#ifdef J2PCSC_DEBUG
{
int k;
printf("-control: 0x%X\n", jControlCode);
printf("-send: ");
for (k = 0; k < sendBufferLength; k++) {
printf("%02x ", sendBuffer[k]);
}
printf("\n");
}
#endif
rv = CALL_SCardControl(card, jControlCode, sendBuffer, sendBufferLength,
receiveBuffer, receiveBufferLength, &returnedLength);
(*env)->ReleaseByteArrayElements(env, jSendBuffer, sendBuffer, JNI_ABORT);
if (handleRV(env, rv)) {
return NULL;
}
#ifdef J2PCSC_DEBUG
{
int k;
printf("-recv: ");
for (k = 0; k < returnedLength; k++) {
printf("%02x ", receiveBuffer[k]);
}
printf("\n");
}
#endif
jReceiveBuffer = (*env)->NewByteArray(env, returnedLength);
if (jReceiveBuffer == NULL) {
return NULL;
}
(*env)->SetByteArrayRegion(env, jReceiveBuffer, 0, returnedLength, receiveBuffer);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
return jReceiveBuffer;
}

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, Red Hat Inc. 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 sun.security.smartcardio;
import java.io.File;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.security.util.Debug;
/**
* Platform specific code and functions for Unix / MUSCLE based PC/SC
* implementations.
*
* @since 1.6
* @author Andreas Sterbenz
*/
class PlatformPCSC {
static final Debug debug = Debug.getInstance("pcsc");
private static final String PROP_NAME = "sun.security.smartcardio.library";
// The architecture templates are for Debian-based systems: https://wiki.debian.org/Multiarch/Tuples
// 32-bit arm differs from the pattern of the rest and has to be specified explicitly
private static final String[] LIB_TEMPLATES = { "/usr/$LIBISA/libpcsclite.so",
"/usr/local/$LIBISA/libpcsclite.so",
"/usr/lib/$ARCH-linux-gnu/libpcsclite.so",
"/usr/lib/arm-linux-gnueabi/libpcsclite.so",
"/usr/lib/arm-linux-gnueabihf/libpcsclite.so" };
private static final String[] LIB_SUFFIXES = { ".1", ".0", "" };
private static final String PCSC_FRAMEWORK = "/System/Library/Frameworks/PCSC.framework/Versions/Current/PCSC";
PlatformPCSC() {
// empty
}
@SuppressWarnings({"removal", "restricted"})
static final Throwable initException
= AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
public Throwable run() {
try {
System.loadLibrary("j2pcsc");
String library = getLibraryName();
if (debug != null) {
debug.println("Using PC/SC library: " + library);
}
initialize(library);
return null;
} catch (Throwable e) {
return e;
}
}
});
// expand $LIBISA to the system specific directory name for libraries
// expand $ARCH to the Debian system architecture in use
private static String expand(String lib) {
int k = lib.indexOf("$LIBISA");
if (k != -1) {
String libDir;
if ("64".equals(System.getProperty("sun.arch.data.model"))) {
// assume Linux convention
libDir = "lib64";
} else {
// must be 32-bit
libDir = "lib";
}
lib = lib.replace("$LIBISA", libDir);
}
k = lib.indexOf("$ARCH");
if (k != -1) {
String arch = System.getProperty("os.arch");
lib = lib.replace("$ARCH", getDebianArchitecture(arch));
}
return lib;
}
private static String getDebianArchitecture(String jdkArch) {
return switch (jdkArch) {
case "amd64" -> "x86_64";
case "ppc" -> "powerpc";
case "ppc64" -> "powerpc64";
case "ppc64le" -> "powerpc64le";
default -> jdkArch;
};
}
private static String getLibraryName() throws IOException {
// if system property is set, use that library
String lib = expand(System.getProperty(PROP_NAME, "").trim());
if (lib.length() != 0) {
return lib;
}
for (String template : LIB_TEMPLATES) {
for (String suffix : LIB_SUFFIXES) {
lib = expand(template) + suffix;
if (debug != null) {
debug.println("Looking for " + lib);
}
if (new File(lib).isFile()) {
// if library exists, use that
return lib;
}
}
}
// As of macos 11, framework libraries have been removed from the file
// system, but in such a way that they can still be dlopen()ed, even
// though they can no longer be open()ed.
//
// https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-release-notes
//
// """New in macOS Big Sur 11.0.1, the system ships with a built-in
// dynamic linker cache of all system-provided libraries. As part of
// this change, copies of dynamic libraries are no longer present on
// the filesystem. Code that attempts to check for dynamic library
// presence by looking for a file at a path or enumerating a directory
// will fail. Instead, check for library presence by attempting to
// dlopen() the path, which will correctly check for the library in the
// cache."""
//
// The directory structure remains otherwise intact, so check for
// existence of the containing directory instead of the file.
lib = PCSC_FRAMEWORK;
if (new File(lib).getParentFile().isDirectory()) {
// if PCSC.framework exists, use that
return lib;
}
throw new IOException("No PC/SC library found on this system");
}
private static native void initialize(String libraryName);
// PCSC constants defined differently under Windows and MUSCLE
// MUSCLE version
static final int SCARD_PROTOCOL_T0 = 0x0001;
static final int SCARD_PROTOCOL_T1 = 0x0002;
static final int SCARD_PROTOCOL_RAW = 0x0004;
static final int SCARD_UNKNOWN = 0x0001;
static final int SCARD_ABSENT = 0x0002;
static final int SCARD_PRESENT = 0x0004;
static final int SCARD_SWALLOWED = 0x0008;
static final int SCARD_POWERED = 0x0010;
static final int SCARD_NEGOTIABLE = 0x0020;
static final int SCARD_SPECIFIC = 0x0040;
}

View file

@ -0,0 +1,57 @@
## PC/SC Lite v2.3.0
### PC/SC Lite Notice
```
MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
Only 3 header files are included in this distribution: winscard.h, wintypes.h, pcsclite.h
Copyright for winscard.h:
* Copyright (C) 1999-2003
* David Corcoran <corcoran@musclecard.com>
* Copyright (C) 2002-2018
* Ludovic Rousseau <ludovic.rousseau@free.fr>
Copyright for wintypes.h:
* Copyright (C) 1999
* David Corcoran <corcoran@musclecard.com>
* Copyright (C) 2002-2018
* Ludovic Rousseau <ludovic.rousseau@free.fr>
Copyright for pcsclite.h:
* Copyright (C) 1999-2004
* David Corcoran <corcoran@musclecard.com>
* Copyright (C) 2002-2024
* Ludovic Rousseau <ludovic.rousseau@free.fr>
* Copyright (C) 2005
* Martin Paljak <martin@paljak.pri.ee>
```
### PC/SC Lite License
```
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```

View file

@ -0,0 +1,29 @@
Copyright (c) 1999-2003 David Corcoran <corcoran@musclecard.com>
Copyright (c) 2001-2011 Ludovic Rousseau <ludovic.rousseau@free.fr>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Some source code files are using other licenses. However, they are not included here and thus this file is a truncated version of the [COPYING](https://salsa.debian.org/rousseau/PCSC/-/blob/master/COPYING) file.

View file

@ -0,0 +1,310 @@
/*
* MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
*
* Copyright (C) 1999-2004
* David Corcoran <corcoran@musclecard.com>
* Copyright (C) 2002-2024
* Ludovic Rousseau <ludovic.rousseau@free.fr>
* Copyright (C) 2005
* Martin Paljak <martin@paljak.pri.ee>
*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief This keeps a list of defines for pcsc-lite.
*
* Error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
*/
#ifndef __pcsclite_h__
#define __pcsclite_h__
#include <wintypes.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef LONG SCARDCONTEXT; /**< \p hContext returned by SCardEstablishContext() */
typedef SCARDCONTEXT *PSCARDCONTEXT;
typedef SCARDCONTEXT *LPSCARDCONTEXT;
typedef LONG SCARDHANDLE; /**< \p hCard returned by SCardConnect() */
typedef SCARDHANDLE *PSCARDHANDLE;
typedef SCARDHANDLE *LPSCARDHANDLE;
#define MAX_ATR_SIZE 33 /**< Maximum ATR size */
/* Set structure elements alignment on bytes
* http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */
#ifdef __APPLE__
#pragma pack(1)
#endif
typedef struct
{
const char *szReader;
void *pvUserData;
DWORD dwCurrentState;
DWORD dwEventState;
DWORD cbAtr;
unsigned char rgbAtr[MAX_ATR_SIZE];
}
SCARD_READERSTATE, *LPSCARD_READERSTATE;
/** Protocol Control Information (PCI) */
typedef struct
{
unsigned long dwProtocol; /**< Protocol identifier */
unsigned long cbPciLength; /**< Protocol Control Inf Length */
}
SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;
typedef const SCARD_IO_REQUEST *LPCSCARD_IO_REQUEST;
extern const SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci;
/* restore default structure elements alignment */
#ifdef __APPLE__
#pragma pack()
#endif
#define SCARD_PCI_T0 (&g_rgSCardT0Pci) /**< protocol control information (PCI) for T=0 */
#define SCARD_PCI_T1 (&g_rgSCardT1Pci) /**< protocol control information (PCI) for T=1 */
#define SCARD_PCI_RAW (&g_rgSCardRawPci) /**< protocol control information (PCI) for RAW protocol */
/**
* @defgroup ErrorCodes ErrorCodes
* @brief Error code documentation
*
* The error codes descriptions are from
* http://msdn.microsoft.com/en-us/library/aa924526.aspx
*/
/** @ingroup ErrorCodes */
#define SCARD_S_SUCCESS ((LONG)0x00000000) /**< No error was encountered. */
/** @ingroup ErrorCodes */
#define SCARD_F_INTERNAL_ERROR ((LONG)0x80100001) /**< An internal consistency check failed. */
/** @ingroup ErrorCodes */
#define SCARD_E_CANCELLED ((LONG)0x80100002) /**< The action was cancelled by an SCardCancel request. */
/** @ingroup ErrorCodes */
#define SCARD_E_INVALID_HANDLE ((LONG)0x80100003) /**< The supplied handle was invalid. */
/** @ingroup ErrorCodes */
#define SCARD_E_INVALID_PARAMETER ((LONG)0x80100004) /**< One or more of the supplied parameters could not be properly interpreted. */
/** @ingroup ErrorCodes */
#define SCARD_E_INVALID_TARGET ((LONG)0x80100005) /**< Registry startup information is missing or invalid. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_MEMORY ((LONG)0x80100006) /**< Not enough memory available to complete this command. */
/** @ingroup ErrorCodes */
#define SCARD_F_WAITED_TOO_LONG ((LONG)0x80100007) /**< An internal consistency timer has expired. */
/** @ingroup ErrorCodes */
#define SCARD_E_INSUFFICIENT_BUFFER ((LONG)0x80100008) /**< The data buffer to receive returned data is too small for the returned data. */
/** @ingroup ErrorCodes */
#define SCARD_E_UNKNOWN_READER ((LONG)0x80100009) /**< The specified reader name is not recognized. */
/** @ingroup ErrorCodes */
#define SCARD_E_TIMEOUT ((LONG)0x8010000A) /**< The user-specified timeout value has expired. */
/** @ingroup ErrorCodes */
#define SCARD_E_SHARING_VIOLATION ((LONG)0x8010000B) /**< The smart card cannot be accessed because of other connections outstanding. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_SMARTCARD ((LONG)0x8010000C) /**< The operation requires a Smart Card, but no Smart Card is currently in the device. */
/** @ingroup ErrorCodes */
#define SCARD_E_UNKNOWN_CARD ((LONG)0x8010000D) /**< The specified smart card name is not recognized. */
/** @ingroup ErrorCodes */
#define SCARD_E_CANT_DISPOSE ((LONG)0x8010000E) /**< The system could not dispose of the media in the requested manner. */
/** @ingroup ErrorCodes */
#define SCARD_E_PROTO_MISMATCH ((LONG)0x8010000F) /**< The requested protocols are incompatible with the protocol currently in use with the smart card. */
/** @ingroup ErrorCodes */
#define SCARD_E_NOT_READY ((LONG)0x80100010) /**< The reader or smart card is not ready to accept commands. */
/** @ingroup ErrorCodes */
#define SCARD_E_INVALID_VALUE ((LONG)0x80100011) /**< One or more of the supplied parameters values could not be properly interpreted. */
/** @ingroup ErrorCodes */
#define SCARD_E_SYSTEM_CANCELLED ((LONG)0x80100012) /**< The action was cancelled by the system, presumably to log off or shut down. */
/** @ingroup ErrorCodes */
#define SCARD_F_COMM_ERROR ((LONG)0x80100013) /**< An internal communications error has been detected. */
/** @ingroup ErrorCodes */
#define SCARD_F_UNKNOWN_ERROR ((LONG)0x80100014) /**< An internal error has been detected, but the source is unknown. */
/** @ingroup ErrorCodes */
#define SCARD_E_INVALID_ATR ((LONG)0x80100015) /**< An ATR obtained from the registry is not a valid ATR string. */
/** @ingroup ErrorCodes */
#define SCARD_E_NOT_TRANSACTED ((LONG)0x80100016) /**< An attempt was made to end a non-existent transaction. */
/** @ingroup ErrorCodes */
#define SCARD_E_READER_UNAVAILABLE ((LONG)0x80100017) /**< The specified reader is not currently available for use. */
/** @ingroup ErrorCodes */
#define SCARD_P_SHUTDOWN ((LONG)0x80100018) /**< The operation has been aborted to allow the server application to exit. */
/** @ingroup ErrorCodes */
#define SCARD_E_PCI_TOO_SMALL ((LONG)0x80100019) /**< The PCI Receive buffer was too small. */
/** @ingroup ErrorCodes */
#define SCARD_E_READER_UNSUPPORTED ((LONG)0x8010001A) /**< The reader driver does not meet minimal requirements for support. */
/** @ingroup ErrorCodes */
#define SCARD_E_DUPLICATE_READER ((LONG)0x8010001B) /**< The reader driver did not produce a unique reader name. */
/** @ingroup ErrorCodes */
#define SCARD_E_CARD_UNSUPPORTED ((LONG)0x8010001C) /**< The smart card does not meet minimal requirements for support. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_SERVICE ((LONG)0x8010001D) /**< The Smart card resource manager is not running. */
/** @ingroup ErrorCodes */
#define SCARD_E_SERVICE_STOPPED ((LONG)0x8010001E) /**< The Smart card resource manager has shut down. */
/** @ingroup ErrorCodes */
#define SCARD_E_UNEXPECTED ((LONG)0x8010001F) /**< An unexpected card error has occurred. */
/** @ingroup ErrorCodes */
#define SCARD_E_UNSUPPORTED_FEATURE ((LONG)0x8010001F) /**< This smart card does not support the requested feature. */
/** @ingroup ErrorCodes */
#define SCARD_E_ICC_INSTALLATION ((LONG)0x80100020) /**< No primary provider can be found for the smart card. */
/** @ingroup ErrorCodes */
#define SCARD_E_ICC_CREATEORDER ((LONG)0x80100021) /**< The requested order of object creation is not supported. */
/** @ingroup ErrorCodes */
/* #define SCARD_E_UNSUPPORTED_FEATURE ((LONG)0x80100022) / **< This smart card does not support the requested feature. */
/** @ingroup ErrorCodes */
#define SCARD_E_DIR_NOT_FOUND ((LONG)0x80100023) /**< The identified directory does not exist in the smart card. */
/** @ingroup ErrorCodes */
#define SCARD_E_FILE_NOT_FOUND ((LONG)0x80100024) /**< The identified file does not exist in the smart card. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_DIR ((LONG)0x80100025) /**< The supplied path does not represent a smart card directory. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_FILE ((LONG)0x80100026) /**< The supplied path does not represent a smart card file. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_ACCESS ((LONG)0x80100027) /**< Access is denied to this file. */
/** @ingroup ErrorCodes */
#define SCARD_E_WRITE_TOO_MANY ((LONG)0x80100028) /**< The smart card does not have enough memory to store the information. */
/** @ingroup ErrorCodes */
#define SCARD_E_BAD_SEEK ((LONG)0x80100029) /**< There was an error trying to set the smart card file object pointer. */
/** @ingroup ErrorCodes */
#define SCARD_E_INVALID_CHV ((LONG)0x8010002A) /**< The supplied PIN is incorrect. */
/** @ingroup ErrorCodes */
#define SCARD_E_UNKNOWN_RES_MSG ((LONG)0x8010002B) /**< An unrecognized error code was returned from a layered component. */
#define SCARD_E_UNKNOWN_RES_MNG SCARD_E_UNKNOWN_RES_MSG
/** @ingroup ErrorCodes */
#define SCARD_E_NO_SUCH_CERTIFICATE ((LONG)0x8010002C) /**< The requested certificate does not exist. */
/** @ingroup ErrorCodes */
#define SCARD_E_CERTIFICATE_UNAVAILABLE ((LONG)0x8010002D) /**< The requested certificate could not be obtained. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_READERS_AVAILABLE ((LONG)0x8010002E) /**< Cannot find a smart card reader. */
/** @ingroup ErrorCodes */
#define SCARD_E_COMM_DATA_LOST ((LONG)0x8010002F) /**< A communications error with the smart card has been detected. Retry the operation. */
/** @ingroup ErrorCodes */
#define SCARD_E_NO_KEY_CONTAINER ((LONG)0x80100030) /**< The requested key container does not exist on the smart card. */
/** @ingroup ErrorCodes */
#define SCARD_E_SERVER_TOO_BUSY ((LONG)0x80100031) /**< The Smart Card Resource Manager is too busy to complete this operation. */
/** @ingroup ErrorCodes */
#define SCARD_W_UNSUPPORTED_CARD ((LONG)0x80100065) /**< The reader cannot communicate with the card, due to ATR string configuration conflicts. */
/** @ingroup ErrorCodes */
#define SCARD_W_UNRESPONSIVE_CARD ((LONG)0x80100066) /**< The smart card is not responding to a reset. */
/** @ingroup ErrorCodes */
#define SCARD_W_UNPOWERED_CARD ((LONG)0x80100067) /**< Power has been removed from the smart card, so that further communication is not possible. */
/** @ingroup ErrorCodes */
#define SCARD_W_RESET_CARD ((LONG)0x80100068) /**< The smart card has been reset, so any shared state information is invalid. */
/** @ingroup ErrorCodes */
#define SCARD_W_REMOVED_CARD ((LONG)0x80100069) /**< The smart card has been removed, so further communication is not possible. */
/** @ingroup ErrorCodes */
#define SCARD_W_SECURITY_VIOLATION ((LONG)0x8010006A) /**< Access was denied because of a security violation. */
/** @ingroup ErrorCodes */
#define SCARD_W_WRONG_CHV ((LONG)0x8010006B) /**< The card cannot be accessed because the wrong PIN was presented. */
/** @ingroup ErrorCodes */
#define SCARD_W_CHV_BLOCKED ((LONG)0x8010006C) /**< The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */
/** @ingroup ErrorCodes */
#define SCARD_W_EOF ((LONG)0x8010006D) /**< The end of the smart card file has been reached. */
/** @ingroup ErrorCodes */
#define SCARD_W_CANCELLED_BY_USER ((LONG)0x8010006E) /**< The user pressed "Cancel" on a Smart Card Selection Dialog. */
/** @ingroup ErrorCodes */
#define SCARD_W_CARD_NOT_AUTHENTICATED ((LONG)0x8010006F) /**< No PIN was presented to the smart card. */
#define SCARD_AUTOALLOCATE (DWORD)(-1) /**< see SCardFreeMemory() */
#define SCARD_SCOPE_USER 0x0000 /**< Scope in user space */
#define SCARD_SCOPE_TERMINAL 0x0001 /**< Scope in terminal */
#define SCARD_SCOPE_SYSTEM 0x0002 /**< Scope in system */
#define SCARD_SCOPE_GLOBAL 0x0003 /**< Scope is global */
#define SCARD_PROTOCOL_UNDEFINED 0x0000 /**< protocol not set */
#define SCARD_PROTOCOL_UNSET SCARD_PROTOCOL_UNDEFINED /* backward compat */
#define SCARD_PROTOCOL_T0 0x0001 /**< T=0 active protocol. */
#define SCARD_PROTOCOL_T1 0x0002 /**< T=1 active protocol. */
#define SCARD_PROTOCOL_RAW 0x0004 /**< Raw active protocol. */
#define SCARD_PROTOCOL_T15 0x0008 /**< T=15 protocol. */
#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1) /**< IFD determines prot. */
#define SCARD_SHARE_EXCLUSIVE 0x0001 /**< Exclusive mode only */
#define SCARD_SHARE_SHARED 0x0002 /**< Shared mode only */
#define SCARD_SHARE_DIRECT 0x0003 /**< Raw mode only */
#define SCARD_LEAVE_CARD 0x0000 /**< Do nothing on close */
#define SCARD_RESET_CARD 0x0001 /**< Reset on close */
#define SCARD_UNPOWER_CARD 0x0002 /**< Power down on close */
#define SCARD_EJECT_CARD 0x0003 /**< Eject on close */
#define SCARD_UNKNOWN 0x0001 /**< Unknown state */
#define SCARD_ABSENT 0x0002 /**< Card is absent */
#define SCARD_PRESENT 0x0004 /**< Card is present */
#define SCARD_SWALLOWED 0x0008 /**< Card not powered */
#define SCARD_POWERED 0x0010 /**< Card is powered */
#define SCARD_NEGOTIABLE 0x0020 /**< Ready for PTS */
#define SCARD_SPECIFIC 0x0040 /**< PTS has been set */
#define SCARD_STATE_UNAWARE 0x0000 /**< App wants status */
#define SCARD_STATE_IGNORE 0x0001 /**< Ignore this reader */
#define SCARD_STATE_CHANGED 0x0002 /**< State has changed */
#define SCARD_STATE_UNKNOWN 0x0004 /**< Reader unknown */
#define SCARD_STATE_UNAVAILABLE 0x0008 /**< Status unavailable */
#define SCARD_STATE_EMPTY 0x0010 /**< Card removed */
#define SCARD_STATE_PRESENT 0x0020 /**< Card inserted */
#define SCARD_STATE_ATRMATCH 0x0040 /**< ATR matches card */
#define SCARD_STATE_EXCLUSIVE 0x0080 /**< Exclusive Mode */
#define SCARD_STATE_INUSE 0x0100 /**< Shared Mode */
#define SCARD_STATE_MUTE 0x0200 /**< Unresponsive card */
#define SCARD_STATE_UNPOWERED 0x0400 /**< Unpowered card */
#ifndef INFINITE
#define INFINITE 0xFFFFFFFF /**< Infinite timeout */
#endif
#define PCSCLITE_VERSION_NUMBER "2.3.0" /**< Current version */
/** Maximum readers context (a slot is count as a reader) */
#define PCSCLITE_MAX_READERS_CONTEXTS 16
#define MAX_READERNAME 128
#ifndef SCARD_ATR_LENGTH
#define SCARD_ATR_LENGTH MAX_ATR_SIZE /**< Maximum ATR size */
#endif
/*
* The message and buffer sizes must be multiples of 16.
* The max message size must be at least large enough
* to accommodate the transmit_struct
*/
#define MAX_BUFFER_SIZE 264 /**< Maximum Tx/Rx Buffer for short APDU */
#define MAX_BUFFER_SIZE_EXTENDED (4 + 3 + (1<<16) + 3 + 2) /**< enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer */
/*
* Gets a stringified error response
*/
const char *pcsc_stringify_error(const LONG);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,122 @@
/*
* MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
*
* Copyright (C) 1999-2003
* David Corcoran <corcoran@musclecard.com>
* Copyright (C) 2002-2018
* Ludovic Rousseau <ludovic.rousseau@free.fr>
*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief This handles smart card reader communications.
*/
#ifndef __winscard_h__
#define __winscard_h__
#include <pcsclite.h>
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef PCSC_API
#define PCSC_API
#endif
PCSC_API LONG SCardEstablishContext(DWORD dwScope,
/*@null@*/ LPCVOID pvReserved1, /*@null@*/ LPCVOID pvReserved2,
/*@out@*/ LPSCARDCONTEXT phContext);
PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext);
PCSC_API LONG SCardIsValidContext(SCARDCONTEXT hContext);
PCSC_API LONG SCardConnect(SCARDCONTEXT hContext,
LPCSTR szReader,
DWORD dwShareMode,
DWORD dwPreferredProtocols,
/*@out@*/ LPSCARDHANDLE phCard, /*@out@*/ LPDWORD pdwActiveProtocol);
PCSC_API LONG SCardReconnect(SCARDHANDLE hCard,
DWORD dwShareMode,
DWORD dwPreferredProtocols,
DWORD dwInitialization, /*@out@*/ LPDWORD pdwActiveProtocol);
PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition);
PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard);
PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition);
PCSC_API LONG SCardStatus(SCARDHANDLE hCard,
/*@null@*/ /*@out@*/ LPSTR mszReaderName,
/*@null@*/ /*@out@*/ LPDWORD pcchReaderLen,
/*@null@*/ /*@out@*/ LPDWORD pdwState,
/*@null@*/ /*@out@*/ LPDWORD pdwProtocol,
/*@null@*/ /*@out@*/ LPBYTE pbAtr,
/*@null@*/ /*@out@*/ LPDWORD pcbAtrLen);
PCSC_API LONG SCardGetStatusChange(SCARDCONTEXT hContext,
DWORD dwTimeout,
SCARD_READERSTATE *rgReaderStates, DWORD cReaders);
PCSC_API LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode,
LPCVOID pbSendBuffer, DWORD cbSendLength,
/*@out@*/ LPVOID pbRecvBuffer, DWORD cbRecvLength,
LPDWORD lpBytesReturned);
PCSC_API LONG SCardTransmit(SCARDHANDLE hCard,
const SCARD_IO_REQUEST *pioSendPci,
LPCBYTE pbSendBuffer, DWORD cbSendLength,
/*@out@*/ SCARD_IO_REQUEST *pioRecvPci,
/*@out@*/ LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength);
PCSC_API LONG SCardListReaderGroups(SCARDCONTEXT hContext,
/*@out@*/ LPSTR mszGroups, LPDWORD pcchGroups);
PCSC_API LONG SCardListReaders(SCARDCONTEXT hContext,
/*@null@*/ /*@out@*/ LPCSTR mszGroups,
/*@null@*/ /*@out@*/ LPSTR mszReaders,
/*@out@*/ LPDWORD pcchReaders);
PCSC_API LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem);
PCSC_API LONG SCardCancel(SCARDCONTEXT hContext);
PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId,
/*@out@*/ LPBYTE pbAttr, LPDWORD pcbAttrLen);
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId,
LPCBYTE pbAttr, DWORD cbAttrLen);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,115 @@
/*
* MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
*
* Copyright (C) 1999
* David Corcoran <corcoran@musclecard.com>
* Copyright (C) 2002-2018
* Ludovic Rousseau <ludovic.rousseau@free.fr>
*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief This keeps a list of Windows(R) types.
*/
#ifndef __wintypes_h__
#define __wintypes_h__
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef __APPLE__
#include <stdint.h>
#ifndef BYTE
typedef uint8_t BYTE;
#endif
typedef uint8_t UCHAR;
typedef UCHAR *PUCHAR;
typedef uint16_t USHORT;
#ifndef __COREFOUNDATION_CFPLUGINCOM__
typedef uint32_t ULONG;
typedef void *LPVOID;
typedef int16_t BOOL;
#endif
typedef ULONG *PULONG;
typedef const void *LPCVOID;
typedef uint32_t DWORD;
typedef DWORD *PDWORD;
typedef uint16_t WORD;
typedef int32_t LONG;
typedef const char *LPCSTR;
typedef const BYTE *LPCBYTE;
typedef BYTE *LPBYTE;
typedef DWORD *LPDWORD;
typedef char *LPSTR;
#else
#ifndef BYTE
typedef unsigned char BYTE;
#endif
typedef unsigned char UCHAR;
typedef UCHAR *PUCHAR;
typedef unsigned short USHORT;
#ifndef __COREFOUNDATION_CFPLUGINCOM__
typedef unsigned long ULONG;
typedef void *LPVOID;
#endif
typedef const void *LPCVOID;
typedef unsigned long DWORD;
typedef DWORD *PDWORD;
typedef long LONG;
typedef const char *LPCSTR;
typedef const BYTE *LPCBYTE;
typedef BYTE *LPBYTE;
typedef DWORD *LPDWORD;
typedef char *LPSTR;
/* these types were deprecated but still used by old drivers and
* applications. So just declare and use them. */
typedef LPSTR LPTSTR;
typedef LPCSTR LPCTSTR;
/* types unused by pcsc-lite */
typedef short BOOL;
typedef unsigned short WORD;
typedef ULONG *PULONG;
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2005, 2023, 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <dlfcn.h>
#include <winscard.h>
#include "sun_security_smartcardio_PlatformPCSC.h"
#include "pcsc_md.h"
void *hModule;
FPTR_SCardEstablishContext scardEstablishContext;
FPTR_SCardConnect scardConnect;
FPTR_SCardDisconnect scardDisconnect;
FPTR_SCardStatus scardStatus;
FPTR_SCardGetStatusChange scardGetStatusChange;
FPTR_SCardTransmit scardTransmit;
FPTR_SCardListReaders scardListReaders;
FPTR_SCardBeginTransaction scardBeginTransaction;
FPTR_SCardEndTransaction scardEndTransaction;
FPTR_SCardControl scardControl;
/*
* Throws a Java Exception by name
*/
static void throwByName(JNIEnv *env, const char *name, const char *msg)
{
jclass cls = (*env)->FindClass(env, name);
if (cls != 0) /* Otherwise an exception has already been thrown */
(*env)->ThrowNew(env, cls, msg);
}
/*
* Throws java.lang.NullPointerException
*/
static void throwNullPointerException(JNIEnv *env, const char *msg)
{
throwByName(env, "java/lang/NullPointerException", msg);
}
/*
* Throws java.io.IOException
*/
static void throwIOException(JNIEnv *env, const char *msg)
{
throwByName(env, "java/io/IOException", msg);
}
static void *findFunction(JNIEnv *env, void *hModule, char *functionName) {
void *fAddress = dlsym(hModule, functionName);
if (fAddress == NULL) {
char errorMessage[256];
snprintf(errorMessage, sizeof(errorMessage), "Symbol not found: %s", functionName);
throwNullPointerException(env, errorMessage);
return NULL;
}
return fAddress;
}
JNIEXPORT void JNICALL Java_sun_security_smartcardio_PlatformPCSC_initialize
(JNIEnv *env, jclass thisClass, jstring jLibName) {
const char *libName = (*env)->GetStringUTFChars(env, jLibName, NULL);
if (libName == NULL) {
throwNullPointerException(env, "PCSC library name is null");
return;
}
hModule = dlopen(libName, RTLD_LAZY);
(*env)->ReleaseStringUTFChars(env, jLibName, libName);
if (hModule == NULL) {
throwIOException(env, dlerror());
return;
}
scardEstablishContext = (FPTR_SCardEstablishContext)findFunction(env, hModule, "SCardEstablishContext");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardConnect = (FPTR_SCardConnect) findFunction(env, hModule, "SCardConnect");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardDisconnect = (FPTR_SCardDisconnect) findFunction(env, hModule, "SCardDisconnect");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardStatus = (FPTR_SCardStatus) findFunction(env, hModule, "SCardStatus");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardGetStatusChange = (FPTR_SCardGetStatusChange) findFunction(env, hModule, "SCardGetStatusChange");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardTransmit = (FPTR_SCardTransmit) findFunction(env, hModule, "SCardTransmit");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardListReaders = (FPTR_SCardListReaders) findFunction(env, hModule, "SCardListReaders");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardBeginTransaction = (FPTR_SCardBeginTransaction)findFunction(env, hModule, "SCardBeginTransaction");
if ((*env)->ExceptionCheck(env)) {
return;
}
scardEndTransaction = (FPTR_SCardEndTransaction) findFunction(env, hModule, "SCardEndTransaction");
if ((*env)->ExceptionCheck(env)) {
return;
}
#ifndef __APPLE__
scardControl = (FPTR_SCardControl) findFunction(env, hModule, "SCardControl");
#else
scardControl = (FPTR_SCardControl) findFunction(env, hModule, "SCardControl132");
#endif // __APPLE__
}

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2005, 2019, 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.
*/
typedef LONG (*FPTR_SCardEstablishContext)(DWORD dwScope,
LPCVOID pvReserved1,
LPCVOID pvReserved2,
LPSCARDCONTEXT phContext);
typedef LONG (*FPTR_SCardConnect)(SCARDCONTEXT hContext,
LPCSTR szReader,
DWORD dwShareMode,
DWORD dwPreferredProtocols,
LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol);
typedef LONG (*FPTR_SCardDisconnect)(SCARDHANDLE hCard, DWORD dwDisposition);
typedef LONG (*FPTR_SCardStatus)(SCARDHANDLE hCard,
LPSTR mszReaderNames,
LPDWORD pcchReaderLen,
LPDWORD pdwState,
LPDWORD pdwProtocol,
LPBYTE pbAtr, LPDWORD pcbAtrLen);
typedef LONG (*FPTR_SCardGetStatusChange)(SCARDCONTEXT hContext,
DWORD dwTimeout,
SCARD_READERSTATE *rgReaderStates, DWORD cReaders);
typedef LONG (*FPTR_SCardTransmit)(SCARDHANDLE hCard,
const SCARD_IO_REQUEST *pioSendPci,
LPCBYTE pbSendBuffer,
DWORD cbSendLength,
SCARD_IO_REQUEST *pioRecvPci,
LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength);
typedef LONG (*FPTR_SCardListReaders)(SCARDCONTEXT hContext,
LPCSTR mszGroups,
LPSTR mszReaders, LPDWORD pcchReaders);
typedef LONG (*FPTR_SCardBeginTransaction)(SCARDHANDLE hCard);
typedef LONG (*FPTR_SCardEndTransaction)(SCARDHANDLE hCard,
DWORD dwDisposition);
typedef LONG (*FPTR_SCardControl)(SCARDHANDLE hCard, DWORD dwControlCode,
LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer,
DWORD pcbRecvLength, LPDWORD lpBytesReturned);
#define CALL_SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext) \
((scardEstablishContext)(dwScope, pvReserved1, pvReserved2, phContext))
#define CALL_SCardConnect(hContext, szReader, dwSharedMode, dwPreferredProtocols, phCard, pdwActiveProtocols) \
((scardConnect)(hContext, szReader, dwSharedMode, dwPreferredProtocols, phCard, pdwActiveProtocols))
#define CALL_SCardDisconnect(hCard, dwDisposition) \
((scardDisconnect)(hCard, dwDisposition))
#define CALL_SCardStatus(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen) \
((scardStatus)(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen))
#define CALL_SCardGetStatusChange(hContext, dwTimeout, rgReaderStates, cReaders) \
((scardGetStatusChange)(hContext, dwTimeout, rgReaderStates, cReaders))
#define CALL_SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength, \
pioRecvPci, pbRecvBuffer, pcbRecvLength) \
((scardTransmit)(hCard, pioSendPci, pbSendBuffer, cbSendLength, \
pioRecvPci, pbRecvBuffer, pcbRecvLength))
#define CALL_SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders) \
((scardListReaders)(hContext, mszGroups, mszReaders, pcchReaders))
#define CALL_SCardBeginTransaction(hCard) \
((scardBeginTransaction)(hCard))
#define CALL_SCardEndTransaction(hCard, dwDisposition) \
((scardEndTransaction)(hCard, dwDisposition))
#define CALL_SCardControl(hCard, dwControlCode, pbSendBuffer, cbSendLength, \
pbRecvBuffer, pcbRecvLength, lpBytesReturned) \
((scardControl)(hCard, dwControlCode, pbSendBuffer, cbSendLength, \
pbRecvBuffer, pcbRecvLength, lpBytesReturned))
extern FPTR_SCardEstablishContext scardEstablishContext;
extern FPTR_SCardConnect scardConnect;
extern FPTR_SCardDisconnect scardDisconnect;
extern FPTR_SCardStatus scardStatus;
extern FPTR_SCardGetStatusChange scardGetStatusChange;
extern FPTR_SCardTransmit scardTransmit;
extern FPTR_SCardListReaders scardListReaders;
extern FPTR_SCardBeginTransaction scardBeginTransaction;
extern FPTR_SCardEndTransaction scardEndTransaction;
extern FPTR_SCardControl scardControl;

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2005, 2024, 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 sun.security.smartcardio;
import java.security.AccessController;
import java.security.PrivilegedAction;
// Platform specific code and constants
class PlatformPCSC {
static final Throwable initException;
PlatformPCSC() {
// empty
}
static {
initException = loadLibrary();
}
@SuppressWarnings({"removal", "restricted"})
private static Throwable loadLibrary() {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("j2pcsc");
return null;
}
});
return null;
} catch (Throwable e) {
return e;
}
}
// PCSC constants defined differently under Windows and MUSCLE
// Windows version
static final int SCARD_PROTOCOL_T0 = 0x0001;
static final int SCARD_PROTOCOL_T1 = 0x0002;
static final int SCARD_PROTOCOL_RAW = 0x10000;
static final int SCARD_UNKNOWN = 0x0000;
static final int SCARD_ABSENT = 0x0001;
static final int SCARD_PRESENT = 0x0002;
static final int SCARD_SWALLOWED = 0x0003;
static final int SCARD_POWERED = 0x0004;
static final int SCARD_NEGOTIABLE = 0x0005;
static final int SCARD_SPECIFIC = 0x0006;
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2005, 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.
*/
/* This file is currently empty */

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2005, 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.
*/
#define CALL_SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext) \
(SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext))
#define CALL_SCardConnect(hContext, szReader, dwSharedMode, dwPreferredProtocols, phCard, pdwActiveProtocols) \
(SCardConnect(hContext, szReader, dwSharedMode, dwPreferredProtocols, phCard, pdwActiveProtocols))
#define CALL_SCardDisconnect(hCard, dwDisposition) \
(SCardDisconnect(hCard, dwDisposition))
#define CALL_SCardStatus(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen) \
(SCardStatus(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen))
#define CALL_SCardGetStatusChange(hContext, dwTimeout, rgReaderStates, cReaders) \
(SCardGetStatusChange(hContext, dwTimeout, rgReaderStates, cReaders))
#define CALL_SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength, \
pioRecvPci, pbRecvBuffer, pcbRecvLength) \
(SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength, \
pioRecvPci, pbRecvBuffer, pcbRecvLength))
#define CALL_SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders) \
(SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders))
#define CALL_SCardBeginTransaction(hCard) \
(SCardBeginTransaction(hCard))
#define CALL_SCardEndTransaction(hCard, dwDisposition) \
(SCardEndTransaction(hCard, dwDisposition))
#define CALL_SCardControl(hCard, dwControlCode, lpInBuffer, nInBufferSize, \
lpOutBuffer, nOutBufferSize, lpBytesReturns) \
(SCardControl(hCard, dwControlCode, lpInBuffer, nInBufferSize, \
lpOutBuffer, nOutBufferSize, lpBytesReturns))