Skip to content

Commit 6c0cd78

Browse files
authored
Merge pull request #154 from arekinath/vpcd-pr
Add basic support for connecting to vsmartcard/vpcd
2 parents 6b438bc + a47a980 commit 6c0cd78

File tree

2 files changed

+256
-0
lines changed

2 files changed

+256
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright 2018 Joyent, Inc
3+
* Copyright 2020 The University of Queensland
4+
* Copyright 2013 Licel LLC.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package com.licel.jcardsim.remote;
19+
20+
import com.licel.jcardsim.base.CardManager;
21+
import com.licel.jcardsim.base.Simulator;
22+
import java.io.FileInputStream;
23+
import java.io.IOException;
24+
import java.security.InvalidParameterException;
25+
import java.util.Enumeration;
26+
import java.util.Properties;
27+
28+
/**
29+
* VSmartCard Card Implementation.
30+
*
31+
32+
*/
33+
public class VSmartCard {
34+
35+
Simulator sim;
36+
37+
public VSmartCard(String host, int port) throws IOException {
38+
VSmartCardTCPProtocol driverProtocol = new VSmartCardTCPProtocol();
39+
driverProtocol.connect(host, port);
40+
startThread(driverProtocol);
41+
}
42+
43+
static public void main(String args[]) throws Exception {
44+
if (args.length !=1) {
45+
System.out.println("Usage: java com.licel.jcardsim.remote.VSmartCard <jcardsim.cfg>");
46+
System.exit(-1);
47+
}
48+
Properties cfg = new Properties();
49+
// init Simulator
50+
FileInputStream fis = null;
51+
try {
52+
fis = new FileInputStream(args[0]);
53+
cfg.load(fis);
54+
} catch (Throwable t) {
55+
System.err.println("Unable to load configuration " + args[0] + " due to: " + t.getMessage());
56+
System.exit(-1);
57+
} finally {
58+
if (fis != null) {
59+
fis.close();
60+
}
61+
}
62+
final Enumeration<?> keys = cfg.propertyNames();
63+
while (keys.hasMoreElements()) {
64+
String propertyName = (String) keys.nextElement();
65+
System.setProperty(propertyName, cfg.getProperty(propertyName));
66+
}
67+
68+
String propKey = "com.licel.jcardsim.vsmartcard.host";
69+
String host = System.getProperty(propKey);
70+
if (host == null) {
71+
throw new InvalidParameterException("Missing value for property: " + propKey);
72+
}
73+
74+
propKey = "com.licel.jcardsim.vsmartcard.port";
75+
String port = System.getProperty(propKey);
76+
if (port == null) {
77+
throw new InvalidParameterException("Missing value for property: " + propKey);
78+
}
79+
80+
new VSmartCard(host, Integer.parseInt(port));
81+
}
82+
83+
private void startThread(VSmartCardTCPProtocol driverProtocol) throws IOException {
84+
sim = new Simulator();
85+
final IOThread ioThread = new IOThread(sim, driverProtocol);
86+
ShutDownHook hook = new ShutDownHook(ioThread);
87+
Runtime.getRuntime().addShutdownHook(hook);
88+
ioThread.start();
89+
}
90+
91+
static class ShutDownHook extends Thread {
92+
IOThread ioThread;
93+
94+
public ShutDownHook(IOThread ioThread) {
95+
this.ioThread = ioThread;
96+
}
97+
98+
public void run() {
99+
ioThread.isRunning = false;
100+
System.out.println("Shutdown connections");
101+
ioThread.driverProtocol.disconnect();
102+
}
103+
}
104+
105+
static class IOThread extends Thread {
106+
VSmartCardTCPProtocol driverProtocol;
107+
Simulator sim;
108+
boolean isRunning;
109+
110+
public IOThread(Simulator sim, VSmartCardTCPProtocol driverProtocol) {
111+
this.sim = sim;
112+
this.driverProtocol = driverProtocol;
113+
isRunning = true;
114+
}
115+
116+
@Override
117+
public void run() {
118+
while (isRunning) {
119+
try {
120+
int cmd = driverProtocol.readCommand();
121+
switch (cmd) {
122+
case VSmartCardTCPProtocol.POWER_ON:
123+
case VSmartCardTCPProtocol.RESET:
124+
sim.reset();
125+
break;
126+
case VSmartCardTCPProtocol.GET_ATR:
127+
driverProtocol.writeData(sim.getATR());
128+
break;
129+
case VSmartCardTCPProtocol.APDU:
130+
final byte[] apdu = driverProtocol.readData();
131+
final byte[] reply = CardManager.dispatchApdu(sim, apdu);
132+
driverProtocol.writeData(reply);
133+
break;
134+
}
135+
} catch (Exception e) {}
136+
}
137+
}
138+
}
139+
140+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright 2018 Joyent, Inc
3+
* Copyright 2020 The University of Queensland
4+
* Copyright 2017 Licel Corporation.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
20+
21+
package com.licel.jcardsim.remote;
22+
23+
import java.io.IOException;
24+
import java.io.InputStream;
25+
import java.io.OutputStream;
26+
27+
import java.net.Socket;
28+
29+
import java.util.concurrent.TimeUnit;
30+
31+
/**
32+
* VSmartCard TCP protocol implementation. Used by VSmartCard.
33+
*
34+
35+
*/
36+
public class VSmartCardTCPProtocol {
37+
private Socket socket;
38+
private InputStream dataInput;
39+
private OutputStream dataOutput;
40+
private int frameLen = -1;
41+
42+
public static final int POWER_OFF = 0;
43+
public static final int POWER_ON = 1;
44+
public static final int RESET = 2;
45+
public static final int GET_ATR = 4;
46+
public static final int APDU = -1;
47+
48+
public void connect(String host, int port) throws IOException {
49+
socket = new Socket(host, port);
50+
51+
try {
52+
TimeUnit.SECONDS.sleep(3);
53+
} catch (InterruptedException ignore) {}
54+
55+
dataInput = socket.getInputStream();
56+
dataOutput = socket.getOutputStream();
57+
}
58+
59+
public void disconnect() {
60+
closeSocket(socket);
61+
}
62+
63+
public int readCommand() throws IOException {
64+
final byte[] cmdBuf = new byte[3];
65+
read(cmdBuf, 0, 2, dataInput);
66+
final int len = ((cmdBuf[0] << 8) & 0xFF00) | (cmdBuf[1] & 0xFF);
67+
if (len == 1) {
68+
read(cmdBuf, 2, 1, dataInput);
69+
final int cmd = cmdBuf[2];
70+
return (cmd);
71+
}
72+
frameLen = len;
73+
return (APDU);
74+
}
75+
76+
public byte[] readData() throws IOException {
77+
if (frameLen == -1) {
78+
throw new IOException("No APDU command waiting");
79+
}
80+
final byte[] buf = new byte[frameLen];
81+
read(buf, dataInput);
82+
frameLen = -1;
83+
return buf;
84+
}
85+
86+
public void writeData(byte[] data) throws IOException {
87+
final byte[] buf = new byte[2 + data.length];
88+
buf[0] = (byte)(((data.length & 0xFF00) >> 8) & 0xFF);
89+
buf[1] = (byte)(data.length & 0xFF);
90+
System.arraycopy(data, 0, buf, 2, data.length);
91+
dataOutput.write(buf);
92+
}
93+
94+
private void closeSocket(Socket sock) {
95+
try {
96+
sock.close();
97+
} catch (IOException ignored) {}
98+
}
99+
100+
private void read(byte[] buf, InputStream stream) throws IOException {
101+
read(buf, 0, buf.length, stream);
102+
}
103+
104+
private void read(byte[] buf, int offset, int len, InputStream stream) throws IOException {
105+
while (len > 0) {
106+
final int retval = stream.read(buf, offset, len);
107+
108+
if (retval < 0) {
109+
throw new IOException("Got negative number from socket");
110+
}
111+
112+
len -= retval;
113+
offset += retval;
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)