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/CardImpl.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.ByteBuffer;
29
import java.security.AccessController;
30
import java.security.PrivilegedAction;
31
import javax.smartcardio.*;
32
import static sun.security.smartcardio.PCSC.*;
33
34
/**
35
* Card implementation.
36
*
37
* @since 1.6
38
* @author Andreas Sterbenz
39
*/
40
final class CardImpl extends Card {
41
42
private static enum State { OK, REMOVED, DISCONNECTED };
43
44
// the terminal that created this card
45
private final TerminalImpl terminal;
46
47
// the native SCARDHANDLE
48
final long cardId;
49
50
// atr of this card
51
private final ATR atr;
52
53
// protocol in use, one of SCARD_PROTOCOL_T0 and SCARD_PROTOCOL_T1
54
final int protocol;
55
56
// the basic logical channel (channel 0)
57
private final ChannelImpl basicChannel;
58
59
// state of this card connection
60
private volatile State state;
61
62
// thread holding exclusive access to the card, or null
63
private volatile Thread exclusiveThread;
64
65
// used for platform specific logic
66
private static final boolean isWindows;
67
68
static {
69
@SuppressWarnings("removal")
70
final String osName = AccessController.doPrivileged(
71
(PrivilegedAction<String>) () -> System.getProperty("os.name"));
72
isWindows = osName.startsWith("Windows");
73
}
74
75
CardImpl(TerminalImpl terminal, String protocol) throws PCSCException {
76
this.terminal = terminal;
77
int sharingMode = SCARD_SHARE_SHARED;
78
int connectProtocol;
79
if (protocol.equals("*")) {
80
connectProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
81
} else if (protocol.equalsIgnoreCase("T=0")) {
82
connectProtocol = SCARD_PROTOCOL_T0;
83
} else if (protocol.equalsIgnoreCase("T=1")) {
84
connectProtocol = SCARD_PROTOCOL_T1;
85
} else if (protocol.equalsIgnoreCase("direct")) {
86
// testing
87
88
// MSDN states that the preferred protocol can be zero, but doesn't
89
// specify whether other values are allowed.
90
// pcsc-lite implementation expects the preferred protocol to be non zero.
91
connectProtocol = isWindows ? 0 : SCARD_PROTOCOL_RAW;
92
93
sharingMode = SCARD_SHARE_DIRECT;
94
} else {
95
throw new IllegalArgumentException("Unsupported protocol " + protocol);
96
}
97
cardId = SCardConnect(terminal.contextId, terminal.name,
98
sharingMode, connectProtocol);
99
byte[] status = new byte[2];
100
byte[] atrBytes = SCardStatus(cardId, status);
101
atr = new ATR(atrBytes);
102
this.protocol = status[1] & 0xff;
103
basicChannel = new ChannelImpl(this, 0);
104
state = State.OK;
105
}
106
107
void checkState() {
108
State s = state;
109
if (s == State.DISCONNECTED) {
110
throw new IllegalStateException("Card has been disconnected");
111
} else if (s == State.REMOVED) {
112
throw new IllegalStateException("Card has been removed");
113
}
114
}
115
116
boolean isValid() {
117
if (state != State.OK) {
118
return false;
119
}
120
// ping card via SCardStatus
121
try {
122
SCardStatus(cardId, new byte[2]);
123
return true;
124
} catch (PCSCException e) {
125
state = State.REMOVED;
126
return false;
127
}
128
}
129
130
private void checkSecurity(String action) {
131
@SuppressWarnings("removal")
132
SecurityManager sm = System.getSecurityManager();
133
if (sm != null) {
134
sm.checkPermission(new CardPermission(terminal.name, action));
135
}
136
}
137
138
void handleError(PCSCException e) {
139
if (e.code == SCARD_W_REMOVED_CARD) {
140
state = State.REMOVED;
141
}
142
}
143
144
public ATR getATR() {
145
return atr;
146
}
147
148
public String getProtocol() {
149
switch (protocol) {
150
case SCARD_PROTOCOL_T0:
151
return "T=0";
152
case SCARD_PROTOCOL_T1:
153
return "T=1";
154
default:
155
// should never occur
156
return "Unknown protocol " + protocol;
157
}
158
}
159
160
public CardChannel getBasicChannel() {
161
checkSecurity("getBasicChannel");
162
checkState();
163
return basicChannel;
164
}
165
166
private static int getSW(byte[] b) {
167
if (b.length < 2) {
168
return -1;
169
}
170
int sw1 = b[b.length - 2] & 0xff;
171
int sw2 = b[b.length - 1] & 0xff;
172
return (sw1 << 8) | sw2;
173
}
174
175
private static byte[] commandOpenChannel = new byte[] {0, 0x70, 0, 0, 1};
176
177
public CardChannel openLogicalChannel() throws CardException {
178
checkSecurity("openLogicalChannel");
179
checkState();
180
checkExclusive();
181
try {
182
byte[] response = SCardTransmit
183
(cardId, protocol, commandOpenChannel, 0, commandOpenChannel.length);
184
if ((response.length != 3) || (getSW(response) != 0x9000)) {
185
throw new CardException
186
("openLogicalChannel() failed, card response: "
187
+ PCSC.toString(response));
188
}
189
return new ChannelImpl(this, response[0]);
190
} catch (PCSCException e) {
191
handleError(e);
192
throw new CardException("openLogicalChannel() failed", e);
193
}
194
}
195
196
void checkExclusive() throws CardException {
197
Thread t = exclusiveThread;
198
if (t == null) {
199
return;
200
}
201
if (t != Thread.currentThread()) {
202
throw new CardException("Exclusive access established by another Thread");
203
}
204
}
205
206
public synchronized void beginExclusive() throws CardException {
207
checkSecurity("exclusive");
208
checkState();
209
if (exclusiveThread != null) {
210
throw new CardException
211
("Exclusive access has already been assigned to Thread "
212
+ exclusiveThread.getName());
213
}
214
try {
215
SCardBeginTransaction(cardId);
216
} catch (PCSCException e) {
217
handleError(e);
218
throw new CardException("beginExclusive() failed", e);
219
}
220
exclusiveThread = Thread.currentThread();
221
}
222
223
public synchronized void endExclusive() throws CardException {
224
checkState();
225
if (exclusiveThread != Thread.currentThread()) {
226
throw new IllegalStateException
227
("Exclusive access not assigned to current Thread");
228
}
229
try {
230
SCardEndTransaction(cardId, SCARD_LEAVE_CARD);
231
} catch (PCSCException e) {
232
handleError(e);
233
throw new CardException("endExclusive() failed", e);
234
} finally {
235
exclusiveThread = null;
236
}
237
}
238
239
public byte[] transmitControlCommand(int controlCode, byte[] command)
240
throws CardException {
241
checkSecurity("transmitControl");
242
checkState();
243
checkExclusive();
244
if (command == null) {
245
throw new NullPointerException();
246
}
247
try {
248
byte[] r = SCardControl(cardId, controlCode, command);
249
return r;
250
} catch (PCSCException e) {
251
handleError(e);
252
throw new CardException("transmitControlCommand() failed", e);
253
}
254
}
255
256
public void disconnect(boolean reset) throws CardException {
257
if (reset) {
258
checkSecurity("reset");
259
}
260
if (state != State.OK) {
261
return;
262
}
263
checkExclusive();
264
try {
265
SCardDisconnect(cardId, (reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD));
266
} catch (PCSCException e) {
267
throw new CardException("disconnect() failed", e);
268
} finally {
269
state = State.DISCONNECTED;
270
exclusiveThread = null;
271
}
272
}
273
274
public String toString() {
275
return "PC/SC card in " + terminal.name
276
+ ", protocol " + getProtocol() + ", state " + state;
277
}
278
279
@SuppressWarnings("deprecation")
280
protected void finalize() throws Throwable {
281
try {
282
if (state == State.OK) {
283
state = State.DISCONNECTED;
284
SCardDisconnect(cardId, SCARD_LEAVE_CARD);
285
}
286
} finally {
287
super.finalize();
288
}
289
}
290
291
}
292
293