Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/smartcardio/CardImpl.java
38829 views
/*1* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.smartcardio;2627import java.nio.ByteBuffer;28import java.security.AccessController;29import java.security.PrivilegedAction;30import javax.smartcardio.*;31import static sun.security.smartcardio.PCSC.*;3233/**34* Card implementation.35*36* @since 1.637* @author Andreas Sterbenz38*/39final class CardImpl extends Card {4041private static enum State { OK, REMOVED, DISCONNECTED };4243// the terminal that created this card44private final TerminalImpl terminal;4546// the native SCARDHANDLE47final long cardId;4849// atr of this card50private final ATR atr;5152// protocol in use, one of SCARD_PROTOCOL_T0 and SCARD_PROTOCOL_T153final int protocol;5455// the basic logical channel (channel 0)56private final ChannelImpl basicChannel;5758// state of this card connection59private volatile State state;6061// thread holding exclusive access to the card, or null62private volatile Thread exclusiveThread;6364// used for platform specific logic65private static final boolean isWindows;6667static {68final String osName = AccessController.doPrivileged(69(PrivilegedAction<String>) () -> System.getProperty("os.name"));70isWindows = osName.startsWith("Windows");71}7273CardImpl(TerminalImpl terminal, String protocol) throws PCSCException {74this.terminal = terminal;75int sharingMode = SCARD_SHARE_SHARED;76int connectProtocol;77if (protocol.equals("*")) {78connectProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;79} else if (protocol.equalsIgnoreCase("T=0")) {80connectProtocol = SCARD_PROTOCOL_T0;81} else if (protocol.equalsIgnoreCase("T=1")) {82connectProtocol = SCARD_PROTOCOL_T1;83} else if (protocol.equalsIgnoreCase("direct")) {84// testing8586// MSDN states that the preferred protocol can be zero, but doesn't87// specify whether other values are allowed.88// pcsc-lite implementation expects the preferred protocol to be non zero.89connectProtocol = isWindows ? 0 : SCARD_PROTOCOL_RAW;9091sharingMode = SCARD_SHARE_DIRECT;92} else {93throw new IllegalArgumentException("Unsupported protocol " + protocol);94}95cardId = SCardConnect(terminal.contextId, terminal.name,96sharingMode, connectProtocol);97byte[] status = new byte[2];98byte[] atrBytes = SCardStatus(cardId, status);99atr = new ATR(atrBytes);100this.protocol = status[1] & 0xff;101basicChannel = new ChannelImpl(this, 0);102state = State.OK;103}104105void checkState() {106State s = state;107if (s == State.DISCONNECTED) {108throw new IllegalStateException("Card has been disconnected");109} else if (s == State.REMOVED) {110throw new IllegalStateException("Card has been removed");111}112}113114boolean isValid() {115if (state != State.OK) {116return false;117}118// ping card via SCardStatus119try {120SCardStatus(cardId, new byte[2]);121return true;122} catch (PCSCException e) {123state = State.REMOVED;124return false;125}126}127128private void checkSecurity(String action) {129SecurityManager sm = System.getSecurityManager();130if (sm != null) {131sm.checkPermission(new CardPermission(terminal.name, action));132}133}134135void handleError(PCSCException e) {136if (e.code == SCARD_W_REMOVED_CARD) {137state = State.REMOVED;138}139}140141public ATR getATR() {142return atr;143}144145public String getProtocol() {146switch (protocol) {147case SCARD_PROTOCOL_T0:148return "T=0";149case SCARD_PROTOCOL_T1:150return "T=1";151default:152// should never occur153return "Unknown protocol " + protocol;154}155}156157public CardChannel getBasicChannel() {158checkSecurity("getBasicChannel");159checkState();160return basicChannel;161}162163private static int getSW(byte[] b) {164if (b.length < 2) {165return -1;166}167int sw1 = b[b.length - 2] & 0xff;168int sw2 = b[b.length - 1] & 0xff;169return (sw1 << 8) | sw2;170}171172private static byte[] commandOpenChannel = new byte[] {0, 0x70, 0, 0, 1};173174public CardChannel openLogicalChannel() throws CardException {175checkSecurity("openLogicalChannel");176checkState();177checkExclusive();178try {179byte[] response = SCardTransmit180(cardId, protocol, commandOpenChannel, 0, commandOpenChannel.length);181if ((response.length != 3) || (getSW(response) != 0x9000)) {182throw new CardException183("openLogicalChannel() failed, card response: "184+ PCSC.toString(response));185}186return new ChannelImpl(this, response[0]);187} catch (PCSCException e) {188handleError(e);189throw new CardException("openLogicalChannel() failed", e);190}191}192193void checkExclusive() throws CardException {194Thread t = exclusiveThread;195if (t == null) {196return;197}198if (t != Thread.currentThread()) {199throw new CardException("Exclusive access established by another Thread");200}201}202203public synchronized void beginExclusive() throws CardException {204checkSecurity("exclusive");205checkState();206if (exclusiveThread != null) {207throw new CardException208("Exclusive access has already been assigned to Thread "209+ exclusiveThread.getName());210}211try {212SCardBeginTransaction(cardId);213} catch (PCSCException e) {214handleError(e);215throw new CardException("beginExclusive() failed", e);216}217exclusiveThread = Thread.currentThread();218}219220public synchronized void endExclusive() throws CardException {221checkState();222if (exclusiveThread != Thread.currentThread()) {223throw new IllegalStateException224("Exclusive access not assigned to current Thread");225}226try {227SCardEndTransaction(cardId, SCARD_LEAVE_CARD);228} catch (PCSCException e) {229handleError(e);230throw new CardException("endExclusive() failed", e);231} finally {232exclusiveThread = null;233}234}235236public byte[] transmitControlCommand(int controlCode, byte[] command)237throws CardException {238checkSecurity("transmitControl");239checkState();240checkExclusive();241if (command == null) {242throw new NullPointerException();243}244try {245byte[] r = SCardControl(cardId, controlCode, command);246return r;247} catch (PCSCException e) {248handleError(e);249throw new CardException("transmitControlCommand() failed", e);250}251}252253private static final boolean invertReset =254Boolean.parseBoolean(255java.security.AccessController.doPrivileged(256new sun.security.action.GetPropertyAction(257"sun.security.smartcardio.invertCardReset", "false")));258259public void disconnect(boolean reset) throws CardException {260if (reset) {261checkSecurity("reset");262}263if (state != State.OK) {264return;265}266checkExclusive();267// to preserve old behaviour, don't change flag until here268if (invertReset) {269reset = !reset;270}271try {272SCardDisconnect(cardId, (reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD));273} catch (PCSCException e) {274throw new CardException("disconnect() failed", e);275} finally {276state = State.DISCONNECTED;277exclusiveThread = null;278}279}280281public String toString() {282return "PC/SC card in " + terminal.name283+ ", protocol " + getProtocol() + ", state " + state;284}285286protected void finalize() throws Throwable {287try {288if (state == State.OK) {289state = State.DISCONNECTED;290SCardDisconnect(cardId, SCARD_LEAVE_CARD);291}292} finally {293super.finalize();294}295}296297}298299300