1 /*
   2  * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.smartcardio;
  27 
  28 import java.nio.*;
  29 import java.security.AccessController;
  30 import java.security.PrivilegedAction;
  31 
  32 import javax.smartcardio.*;
  33 
  34 import static sun.security.smartcardio.PCSC.*;
  35 
  36 /**
  37  * CardChannel implementation.
  38  *
  39  * @since   1.6
  40  * @author  Andreas Sterbenz
  41  */
  42 final class ChannelImpl extends CardChannel {
  43 
  44     // the card this channel is associated with
  45     private final CardImpl card;
  46 
  47     // the channel number, 0 for the basic logical channel
  48     private final int channel;
  49 
  50     // whether this channel has been closed. only logical channels can be closed
  51     private volatile boolean isClosed;
  52 
  53     ChannelImpl(CardImpl card, int channel) {
  54         this.card = card;
  55         this.channel = channel;
  56     }
  57 
  58     void checkClosed() {
  59         card.checkState();
  60         if (isClosed) {
  61             throw new IllegalStateException("Logical channel has been closed");
  62         }
  63     }
  64 
  65     public Card getCard() {
  66         return card;
  67     }
  68 
  69     public int getChannelNumber() {
  70         checkClosed();
  71         return channel;
  72     }
  73 
  74     private static void checkManageChannel(byte[] b) {
  75         if (b.length < 4) {
  76             throw new IllegalArgumentException
  77                 ("Command APDU must be at least 4 bytes long");
  78         }
  79         if ((b[0] >= 0) && (b[1] == 0x70)) {
  80             throw new IllegalArgumentException
  81                 ("Manage channel command not allowed, use openLogicalChannel()");
  82         }
  83     }
  84 
  85     public ResponseAPDU transmit(CommandAPDU command) throws CardException {
  86         checkClosed();
  87         card.checkExclusive();
  88         byte[] commandBytes = command.getBytes();
  89         byte[] responseBytes = doTransmit(commandBytes);
  90         return new ResponseAPDU(responseBytes);
  91     }
  92 
  93     public int transmit(ByteBuffer command, ByteBuffer response) throws CardException {
  94         checkClosed();
  95         card.checkExclusive();
  96         if ((command == null) || (response == null)) {
  97             throw new NullPointerException();
  98         }
  99         if (response.isReadOnly()) {
 100             throw new ReadOnlyBufferException();
 101         }
 102         if (command == response) {
 103             throw new IllegalArgumentException
 104                     ("command and response must not be the same object");
 105         }
 106         if (response.remaining() < 258) {
 107             throw new IllegalArgumentException
 108                     ("Insufficient space in response buffer");
 109         }
 110         byte[] commandBytes = new byte[command.remaining()];
 111         command.get(commandBytes);
 112         byte[] responseBytes = doTransmit(commandBytes);
 113         response.put(responseBytes);
 114         return responseBytes.length;
 115     }
 116 
 117     private final static boolean t0GetResponse =
 118         getBooleanProperty("sun.security.smartcardio.t0GetResponse", true);
 119 
 120     private final static boolean t1GetResponse =
 121         getBooleanProperty("sun.security.smartcardio.t1GetResponse", true);
 122 
 123     private final static boolean t1StripLe =
 124         getBooleanProperty("sun.security.smartcardio.t1StripLe", false);
 125 
 126     private static boolean getBooleanProperty(String name, boolean def) {
 127         String val = AccessController.doPrivileged(
 128             (PrivilegedAction<String>) () -> System.getProperty(name));
 129         if (val == null) {
 130             return def;
 131         }
 132         if (val.equalsIgnoreCase("true")) {
 133             return true;
 134         } else if (val.equalsIgnoreCase("false")) {
 135             return false;
 136         } else {
 137             throw new IllegalArgumentException
 138                 (name + " must be either 'true' or 'false'");
 139         }
 140     }
 141 
 142     private byte[] concat(byte[] b1, byte[] b2, int n2) {
 143         int n1 = b1.length;
 144         if ((n1 == 0) && (n2 == b2.length)) {
 145             return b2;
 146         }
 147         byte[] res = new byte[n1 + n2];
 148         System.arraycopy(b1, 0, res, 0, n1);
 149         System.arraycopy(b2, 0, res, n1, n2);
 150         return res;
 151     }
 152 
 153     private final static byte[] B0 = new byte[0];
 154 
 155     private byte[] doTransmit(byte[] command) throws CardException {
 156         // note that we modify the 'command' array in some cases, so it must
 157         // be a copy of the application provided data.
 158         try {
 159             checkManageChannel(command);
 160             setChannel(command);
 161             int n = command.length;
 162             boolean t0 = card.protocol == SCARD_PROTOCOL_T0;
 163             boolean t1 = card.protocol == SCARD_PROTOCOL_T1;
 164             if (t0 && (n >= 7) && (command[4] == 0)) {
 165                 throw new CardException
 166                         ("Extended length forms not supported for T=0");
 167             }
 168             if ((t0 || (t1 && t1StripLe)) && (n >= 7)) {
 169                 int lc = command[4] & 0xff;
 170                 if (lc != 0) {
 171                     if (n == lc + 6) {
 172                         n--;
 173                     }
 174                 } else {
 175                     lc = ((command[5] & 0xff) << 8) | (command[6] & 0xff);
 176                     if (n == lc + 9) {
 177                         n -= 2;
 178                     }
 179                 }
 180             }
 181             boolean getresponse = (t0 && t0GetResponse) || (t1 && t1GetResponse);
 182             int k = 0;
 183             byte[] result = B0;
 184             while (true) {
 185                 if (++k >= 32) {
 186                     throw new CardException("Could not obtain response");
 187                 }
 188                 byte[] response = SCardTransmit
 189                     (card.cardId, card.protocol, command, 0, n);
 190                 int rn = response.length;
 191                 if (getresponse && (rn >= 2)) {
 192                     // see ISO 7816/2005, 5.1.3
 193                     if ((rn == 2) && (response[0] == 0x6c)) {
 194                         // Resend command using SW2 as short Le field
 195                         command[n - 1] = response[1];
 196                         continue;
 197                     }
 198                     if (response[rn - 2] == 0x61) {
 199                         // Issue a GET RESPONSE command with the same CLA
 200                         // using SW2 as short Le field
 201                         if (rn > 2) {
 202                             result = concat(result, response, rn - 2);
 203                         }
 204                         command[1] = (byte)0xC0;
 205                         command[2] = 0;
 206                         command[3] = 0;
 207                         command[4] = response[rn - 1];
 208                         n = 5;
 209                         continue;
 210                     }
 211 
 212                 }
 213                 result = concat(result, response, rn);
 214                 break;
 215             }
 216             return result;
 217         } catch (PCSCException e) {
 218             card.handleError(e);
 219             throw new CardException(e);
 220         }
 221     }
 222 
 223     private static int getSW(byte[] res) throws CardException {
 224         if (res.length < 2) {
 225             throw new CardException("Invalid response length: " + res.length);
 226         }
 227         int sw1 = res[res.length - 2] & 0xff;
 228         int sw2 = res[res.length - 1] & 0xff;
 229         return (sw1 << 8) | sw2;
 230     }
 231 
 232     private static boolean isOK(byte[] res) throws CardException {
 233         return (res.length == 2) && (getSW(res) == 0x9000);
 234     }
 235 
 236     private void setChannel(byte[] com) {
 237         int cla = com[0];
 238         if (cla < 0) {
 239             // proprietary class format, cannot set or check logical channel
 240             // for now, just return
 241             return;
 242         }
 243         // classes 001x xxxx is reserved for future use in ISO, ignore
 244         if ((cla & 0xe0) == 0x20) {
 245             return;
 246         }
 247         // see ISO 7816/2005, table 2 and 3
 248         if (channel <= 3) {
 249             // mask of bits 7, 1, 0 (channel number)
 250             // 0xbc == 1011 1100
 251             com[0] &= 0xbc;
 252             com[0] |= channel;
 253         } else if (channel <= 19) {
 254             // mask of bits 7, 3, 2, 1, 0 (channel number)
 255             // 0xbc == 1011 0000
 256             com[0] &= 0xb0;
 257             com[0] |= 0x40;
 258             com[0] |= (channel - 4);
 259         } else {
 260             throw new RuntimeException("Unsupported channel number: " + channel);
 261         }
 262     }
 263 
 264     public void close() throws CardException {
 265         if (getChannelNumber() == 0) {
 266             throw new IllegalStateException("Cannot close basic logical channel");
 267         }
 268         if (isClosed) {
 269             return;
 270         }
 271         card.checkExclusive();
 272         try {
 273             byte[] com = new byte[] {0x00, 0x70, (byte)0x80, 0};
 274             com[3] = (byte)getChannelNumber();
 275             setChannel(com);
 276             byte[] res = SCardTransmit(card.cardId, card.protocol, com, 0, com.length);
 277             if (isOK(res) == false) {
 278                 throw new CardException("close() failed: " + PCSC.toString(res));
 279             }
 280         } catch (PCSCException e) {
 281             card.handleError(e);
 282             throw new CardException("Could not close channel", e);
 283         } finally {
 284             isClosed = true;
 285         }
 286     }
 287 
 288     public String toString() {
 289         return "PC/SC channel " + channel;
 290     }
 291 
 292 }