Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.smartcardio/share/classes/sun/security/smartcardio/ChannelImpl.java
41159 views
1
/*
2
* Copyright (c) 2005, 2021, 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
@SuppressWarnings("removal")
128
String val = AccessController.doPrivileged(
129
(PrivilegedAction<String>) () -> System.getProperty(name));
130
if (val == null) {
131
return def;
132
}
133
if (val.equalsIgnoreCase("true")) {
134
return true;
135
} else if (val.equalsIgnoreCase("false")) {
136
return false;
137
} else {
138
throw new IllegalArgumentException
139
(name + " must be either 'true' or 'false'");
140
}
141
}
142
143
private byte[] concat(byte[] b1, byte[] b2, int n2) {
144
int n1 = b1.length;
145
if ((n1 == 0) && (n2 == b2.length)) {
146
return b2;
147
}
148
byte[] res = new byte[n1 + n2];
149
System.arraycopy(b1, 0, res, 0, n1);
150
System.arraycopy(b2, 0, res, n1, n2);
151
return res;
152
}
153
154
private final static int RESPONSE_ITERATIONS = 256;
155
private final static byte[] B0 = new byte[0];
156
157
private byte[] doTransmit(byte[] command) throws CardException {
158
// note that we modify the 'command' array in some cases, so it must
159
// be a copy of the application provided data.
160
try {
161
checkManageChannel(command);
162
setChannel(command);
163
int n = command.length;
164
boolean t0 = card.protocol == SCARD_PROTOCOL_T0;
165
boolean t1 = card.protocol == SCARD_PROTOCOL_T1;
166
if (t0 && (n >= 7) && (command[4] == 0)) {
167
throw new CardException
168
("Extended length forms not supported for T=0");
169
}
170
if ((t0 || (t1 && t1StripLe)) && (n >= 7)) {
171
int lc = command[4] & 0xff;
172
if (lc != 0) {
173
if (n == lc + 6) {
174
n--;
175
}
176
} else {
177
lc = ((command[5] & 0xff) << 8) | (command[6] & 0xff);
178
if (n == lc + 9) {
179
n -= 2;
180
}
181
}
182
}
183
boolean getresponse = (t0 && t0GetResponse) || (t1 && t1GetResponse);
184
int k = 0;
185
byte[] result = B0;
186
while (true) {
187
if (++k > RESPONSE_ITERATIONS) {
188
throw new CardException("Number of response iterations" +
189
" exceeded maximum " + RESPONSE_ITERATIONS);
190
}
191
byte[] response = SCardTransmit
192
(card.cardId, card.protocol, command, 0, n);
193
int rn = response.length;
194
if (getresponse && (rn >= 2) && (n >= 1)) {
195
// see ISO 7816/2005, 5.1.3
196
if ((rn == 2) && (response[0] == 0x6c)) {
197
// Resend command using SW2 as short Le field
198
command[n - 1] = response[1];
199
continue;
200
}
201
if (response[rn - 2] == 0x61) {
202
// Issue a GET RESPONSE command with the same CLA
203
// using SW2 as short Le field
204
if (rn > 2) {
205
result = concat(result, response, rn - 2);
206
}
207
if (command.length < 5) {
208
byte cla = command[0];
209
command = new byte[5];
210
command[0] = cla;
211
}
212
command[1] = (byte)0xC0;
213
command[2] = 0;
214
command[3] = 0;
215
command[4] = response[rn - 1];
216
n = 5;
217
continue;
218
}
219
}
220
result = concat(result, response, rn);
221
break;
222
}
223
return result;
224
} catch (PCSCException e) {
225
card.handleError(e);
226
throw new CardException(e);
227
}
228
}
229
230
private static int getSW(byte[] res) throws CardException {
231
if (res.length < 2) {
232
throw new CardException("Invalid response length: " + res.length);
233
}
234
int sw1 = res[res.length - 2] & 0xff;
235
int sw2 = res[res.length - 1] & 0xff;
236
return (sw1 << 8) | sw2;
237
}
238
239
private static boolean isOK(byte[] res) throws CardException {
240
return (res.length == 2) && (getSW(res) == 0x9000);
241
}
242
243
private void setChannel(byte[] com) {
244
int cla = com[0];
245
if (cla < 0) {
246
// proprietary class format, cannot set or check logical channel
247
// for now, just return
248
return;
249
}
250
// classes 001x xxxx is reserved for future use in ISO, ignore
251
if ((cla & 0xe0) == 0x20) {
252
return;
253
}
254
// see ISO 7816/2005, table 2 and 3
255
if (channel <= 3) {
256
// mask of bits 7, 1, 0 (channel number)
257
// 0xbc == 1011 1100
258
com[0] &= 0xbc;
259
com[0] |= channel;
260
} else if (channel <= 19) {
261
// mask of bits 7, 3, 2, 1, 0 (channel number)
262
// 0xbc == 1011 0000
263
com[0] &= 0xb0;
264
com[0] |= 0x40;
265
com[0] |= (channel - 4);
266
} else {
267
throw new RuntimeException("Unsupported channel number: " + channel);
268
}
269
}
270
271
public void close() throws CardException {
272
if (getChannelNumber() == 0) {
273
throw new IllegalStateException("Cannot close basic logical channel");
274
}
275
if (isClosed) {
276
return;
277
}
278
card.checkExclusive();
279
try {
280
byte[] com = new byte[] {0x00, 0x70, (byte)0x80, 0};
281
com[3] = (byte)getChannelNumber();
282
setChannel(com);
283
byte[] res = SCardTransmit(card.cardId, card.protocol, com, 0, com.length);
284
if (isOK(res) == false) {
285
throw new CardException("close() failed: " + PCSC.toString(res));
286
}
287
} catch (PCSCException e) {
288
card.handleError(e);
289
throw new CardException("Could not close channel", e);
290
} finally {
291
isClosed = true;
292
}
293
}
294
295
public String toString() {
296
return "PC/SC channel " + channel;
297
}
298
299
}
300
301