Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/smartcardio/ChannelImpl.java
38829 views
/*1* Copyright (c) 2005, 2020, 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.*;28import java.security.AccessController;2930import javax.smartcardio.*;3132import static sun.security.smartcardio.PCSC.*;3334import sun.security.action.GetPropertyAction;3536/**37* CardChannel implementation.38*39* @since 1.640* @author Andreas Sterbenz41*/42final class ChannelImpl extends CardChannel {4344// the card this channel is associated with45private final CardImpl card;4647// the channel number, 0 for the basic logical channel48private final int channel;4950// whether this channel has been closed. only logical channels can be closed51private volatile boolean isClosed;5253ChannelImpl(CardImpl card, int channel) {54this.card = card;55this.channel = channel;56}5758void checkClosed() {59card.checkState();60if (isClosed) {61throw new IllegalStateException("Logical channel has been closed");62}63}6465public Card getCard() {66return card;67}6869public int getChannelNumber() {70checkClosed();71return channel;72}7374private static void checkManageChannel(byte[] b) {75if (b.length < 4) {76throw new IllegalArgumentException77("Command APDU must be at least 4 bytes long");78}79if ((b[0] >= 0) && (b[1] == 0x70)) {80throw new IllegalArgumentException81("Manage channel command not allowed, use openLogicalChannel()");82}83}8485public ResponseAPDU transmit(CommandAPDU command) throws CardException {86checkClosed();87card.checkExclusive();88byte[] commandBytes = command.getBytes();89byte[] responseBytes = doTransmit(commandBytes);90return new ResponseAPDU(responseBytes);91}9293public int transmit(ByteBuffer command, ByteBuffer response) throws CardException {94checkClosed();95card.checkExclusive();96if ((command == null) || (response == null)) {97throw new NullPointerException();98}99if (response.isReadOnly()) {100throw new ReadOnlyBufferException();101}102if (command == response) {103throw new IllegalArgumentException104("command and response must not be the same object");105}106if (response.remaining() < 258) {107throw new IllegalArgumentException108("Insufficient space in response buffer");109}110byte[] commandBytes = new byte[command.remaining()];111command.get(commandBytes);112byte[] responseBytes = doTransmit(commandBytes);113response.put(responseBytes);114return responseBytes.length;115}116117private final static boolean t0GetResponse =118getBooleanProperty("sun.security.smartcardio.t0GetResponse", true);119120private final static boolean t1GetResponse =121getBooleanProperty("sun.security.smartcardio.t1GetResponse", true);122123private final static boolean t1StripLe =124getBooleanProperty("sun.security.smartcardio.t1StripLe", false);125126private static boolean getBooleanProperty(String name, boolean def) {127String val = AccessController.doPrivileged(new GetPropertyAction(name));128if (val == null) {129return def;130}131if (val.equalsIgnoreCase("true")) {132return true;133} else if (val.equalsIgnoreCase("false")) {134return false;135} else {136throw new IllegalArgumentException137(name + " must be either 'true' or 'false'");138}139}140141private byte[] concat(byte[] b1, byte[] b2, int n2) {142int n1 = b1.length;143if ((n1 == 0) && (n2 == b2.length)) {144return b2;145}146byte[] res = new byte[n1 + n2];147System.arraycopy(b1, 0, res, 0, n1);148System.arraycopy(b2, 0, res, n1, n2);149return res;150}151152private final static int RESPONSE_ITERATIONS = 256;153private final static byte[] B0 = new byte[0];154155private byte[] doTransmit(byte[] command) throws CardException {156// note that we modify the 'command' array in some cases, so it must157// be a copy of the application provided data.158try {159checkManageChannel(command);160setChannel(command);161int n = command.length;162boolean t0 = card.protocol == SCARD_PROTOCOL_T0;163boolean t1 = card.protocol == SCARD_PROTOCOL_T1;164if (t0 && (n >= 7) && (command[4] == 0)) {165throw new CardException166("Extended length forms not supported for T=0");167}168if ((t0 || (t1 && t1StripLe)) && (n >= 7)) {169int lc = command[4] & 0xff;170if (lc != 0) {171if (n == lc + 6) {172n--;173}174} else {175lc = ((command[5] & 0xff) << 8) | (command[6] & 0xff);176if (n == lc + 9) {177n -= 2;178}179}180}181boolean getresponse = (t0 && t0GetResponse) || (t1 && t1GetResponse);182int k = 0;183byte[] result = B0;184while (true) {185if (++k > RESPONSE_ITERATIONS) {186throw new CardException("Number of response iterations" +187" exceeded maximum " + RESPONSE_ITERATIONS);188}189byte[] response = SCardTransmit190(card.cardId, card.protocol, command, 0, n);191int rn = response.length;192if (getresponse && (rn >= 2)) {193// see ISO 7816/2005, 5.1.3194if ((rn == 2) && (response[0] == 0x6c)) {195// Resend command using SW2 as short Le field196command[n - 1] = response[1];197continue;198}199if (response[rn - 2] == 0x61) {200// Issue a GET RESPONSE command with the same CLA201// using SW2 as short Le field202if (rn > 2) {203result = concat(result, response, rn - 2);204}205command[1] = (byte)0xC0;206command[2] = 0;207command[3] = 0;208command[4] = response[rn - 1];209n = 5;210continue;211}212213}214result = concat(result, response, rn);215break;216}217return result;218} catch (PCSCException e) {219card.handleError(e);220throw new CardException(e);221}222}223224private static int getSW(byte[] res) throws CardException {225if (res.length < 2) {226throw new CardException("Invalid response length: " + res.length);227}228int sw1 = res[res.length - 2] & 0xff;229int sw2 = res[res.length - 1] & 0xff;230return (sw1 << 8) | sw2;231}232233private static boolean isOK(byte[] res) throws CardException {234return (res.length == 2) && (getSW(res) == 0x9000);235}236237private void setChannel(byte[] com) {238int cla = com[0];239if (cla < 0) {240// proprietary class format, cannot set or check logical channel241// for now, just return242return;243}244// classes 001x xxxx is reserved for future use in ISO, ignore245if ((cla & 0xe0) == 0x20) {246return;247}248// see ISO 7816/2005, table 2 and 3249if (channel <= 3) {250// mask of bits 7, 1, 0 (channel number)251// 0xbc == 1011 1100252com[0] &= 0xbc;253com[0] |= channel;254} else if (channel <= 19) {255// mask of bits 7, 3, 2, 1, 0 (channel number)256// 0xbc == 1011 0000257com[0] &= 0xb0;258com[0] |= 0x40;259com[0] |= (channel - 4);260} else {261throw new RuntimeException("Unsupported channel number: " + channel);262}263}264265public void close() throws CardException {266if (getChannelNumber() == 0) {267throw new IllegalStateException("Cannot close basic logical channel");268}269if (isClosed) {270return;271}272card.checkExclusive();273try {274byte[] com = new byte[] {0x00, 0x70, (byte)0x80, 0};275com[3] = (byte)getChannelNumber();276setChannel(com);277byte[] res = SCardTransmit(card.cardId, card.protocol, com, 0, com.length);278if (isOK(res) == false) {279throw new CardException("close() failed: " + PCSC.toString(res));280}281} catch (PCSCException e) {282card.handleError(e);283throw new CardException("Could not close channel", e);284} finally {285isClosed = true;286}287}288289public String toString() {290return "PC/SC channel " + channel;291}292293}294295296