Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/smartcardio/CardImpl.java
38829 views
1
/*
2
* Copyright (c) 2005, 2016, 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
final String osName = AccessController.doPrivileged(
70
(PrivilegedAction<String>) () -> System.getProperty("os.name"));
71
isWindows = osName.startsWith("Windows");
72
}
73
74
CardImpl(TerminalImpl terminal, String protocol) throws PCSCException {
75
this.terminal = terminal;
76
int sharingMode = SCARD_SHARE_SHARED;
77
int connectProtocol;
78
if (protocol.equals("*")) {
79
connectProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
80
} else if (protocol.equalsIgnoreCase("T=0")) {
81
connectProtocol = SCARD_PROTOCOL_T0;
82
} else if (protocol.equalsIgnoreCase("T=1")) {
83
connectProtocol = SCARD_PROTOCOL_T1;
84
} else if (protocol.equalsIgnoreCase("direct")) {
85
// testing
86
87
// MSDN states that the preferred protocol can be zero, but doesn't
88
// specify whether other values are allowed.
89
// pcsc-lite implementation expects the preferred protocol to be non zero.
90
connectProtocol = isWindows ? 0 : SCARD_PROTOCOL_RAW;
91
92
sharingMode = SCARD_SHARE_DIRECT;
93
} else {
94
throw new IllegalArgumentException("Unsupported protocol " + protocol);
95
}
96
cardId = SCardConnect(terminal.contextId, terminal.name,
97
sharingMode, connectProtocol);
98
byte[] status = new byte[2];
99
byte[] atrBytes = SCardStatus(cardId, status);
100
atr = new ATR(atrBytes);
101
this.protocol = status[1] & 0xff;
102
basicChannel = new ChannelImpl(this, 0);
103
state = State.OK;
104
}
105
106
void checkState() {
107
State s = state;
108
if (s == State.DISCONNECTED) {
109
throw new IllegalStateException("Card has been disconnected");
110
} else if (s == State.REMOVED) {
111
throw new IllegalStateException("Card has been removed");
112
}
113
}
114
115
boolean isValid() {
116
if (state != State.OK) {
117
return false;
118
}
119
// ping card via SCardStatus
120
try {
121
SCardStatus(cardId, new byte[2]);
122
return true;
123
} catch (PCSCException e) {
124
state = State.REMOVED;
125
return false;
126
}
127
}
128
129
private void checkSecurity(String action) {
130
SecurityManager sm = System.getSecurityManager();
131
if (sm != null) {
132
sm.checkPermission(new CardPermission(terminal.name, action));
133
}
134
}
135
136
void handleError(PCSCException e) {
137
if (e.code == SCARD_W_REMOVED_CARD) {
138
state = State.REMOVED;
139
}
140
}
141
142
public ATR getATR() {
143
return atr;
144
}
145
146
public String getProtocol() {
147
switch (protocol) {
148
case SCARD_PROTOCOL_T0:
149
return "T=0";
150
case SCARD_PROTOCOL_T1:
151
return "T=1";
152
default:
153
// should never occur
154
return "Unknown protocol " + protocol;
155
}
156
}
157
158
public CardChannel getBasicChannel() {
159
checkSecurity("getBasicChannel");
160
checkState();
161
return basicChannel;
162
}
163
164
private static int getSW(byte[] b) {
165
if (b.length < 2) {
166
return -1;
167
}
168
int sw1 = b[b.length - 2] & 0xff;
169
int sw2 = b[b.length - 1] & 0xff;
170
return (sw1 << 8) | sw2;
171
}
172
173
private static byte[] commandOpenChannel = new byte[] {0, 0x70, 0, 0, 1};
174
175
public CardChannel openLogicalChannel() throws CardException {
176
checkSecurity("openLogicalChannel");
177
checkState();
178
checkExclusive();
179
try {
180
byte[] response = SCardTransmit
181
(cardId, protocol, commandOpenChannel, 0, commandOpenChannel.length);
182
if ((response.length != 3) || (getSW(response) != 0x9000)) {
183
throw new CardException
184
("openLogicalChannel() failed, card response: "
185
+ PCSC.toString(response));
186
}
187
return new ChannelImpl(this, response[0]);
188
} catch (PCSCException e) {
189
handleError(e);
190
throw new CardException("openLogicalChannel() failed", e);
191
}
192
}
193
194
void checkExclusive() throws CardException {
195
Thread t = exclusiveThread;
196
if (t == null) {
197
return;
198
}
199
if (t != Thread.currentThread()) {
200
throw new CardException("Exclusive access established by another Thread");
201
}
202
}
203
204
public synchronized void beginExclusive() throws CardException {
205
checkSecurity("exclusive");
206
checkState();
207
if (exclusiveThread != null) {
208
throw new CardException
209
("Exclusive access has already been assigned to Thread "
210
+ exclusiveThread.getName());
211
}
212
try {
213
SCardBeginTransaction(cardId);
214
} catch (PCSCException e) {
215
handleError(e);
216
throw new CardException("beginExclusive() failed", e);
217
}
218
exclusiveThread = Thread.currentThread();
219
}
220
221
public synchronized void endExclusive() throws CardException {
222
checkState();
223
if (exclusiveThread != Thread.currentThread()) {
224
throw new IllegalStateException
225
("Exclusive access not assigned to current Thread");
226
}
227
try {
228
SCardEndTransaction(cardId, SCARD_LEAVE_CARD);
229
} catch (PCSCException e) {
230
handleError(e);
231
throw new CardException("endExclusive() failed", e);
232
} finally {
233
exclusiveThread = null;
234
}
235
}
236
237
public byte[] transmitControlCommand(int controlCode, byte[] command)
238
throws CardException {
239
checkSecurity("transmitControl");
240
checkState();
241
checkExclusive();
242
if (command == null) {
243
throw new NullPointerException();
244
}
245
try {
246
byte[] r = SCardControl(cardId, controlCode, command);
247
return r;
248
} catch (PCSCException e) {
249
handleError(e);
250
throw new CardException("transmitControlCommand() failed", e);
251
}
252
}
253
254
private static final boolean invertReset =
255
Boolean.parseBoolean(
256
java.security.AccessController.doPrivileged(
257
new sun.security.action.GetPropertyAction(
258
"sun.security.smartcardio.invertCardReset", "false")));
259
260
public void disconnect(boolean reset) throws CardException {
261
if (reset) {
262
checkSecurity("reset");
263
}
264
if (state != State.OK) {
265
return;
266
}
267
checkExclusive();
268
// to preserve old behaviour, don't change flag until here
269
if (invertReset) {
270
reset = !reset;
271
}
272
try {
273
SCardDisconnect(cardId, (reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD));
274
} catch (PCSCException e) {
275
throw new CardException("disconnect() failed", e);
276
} finally {
277
state = State.DISCONNECTED;
278
exclusiveThread = null;
279
}
280
}
281
282
public String toString() {
283
return "PC/SC card in " + terminal.name
284
+ ", protocol " + getProtocol() + ", state " + state;
285
}
286
287
protected void finalize() throws Throwable {
288
try {
289
if (state == State.OK) {
290
state = State.DISCONNECTED;
291
SCardDisconnect(cardId, SCARD_LEAVE_CARD);
292
}
293
} finally {
294
super.finalize();
295
}
296
}
297
298
}
299
300