Project

General

Profile

Download (7.97 KB) Statistics
| Branch: | Revision:
1
/* Copyright 2020 sysmocom s.f.m.c. GmbH
2
 * SPDX-License-Identifier: Apache-2.0 */
3
package org.osmocom.IMSIPseudo;
4
import org.osmocom.IMSIPseudo.MobileIdentity;
5

    
6
import sim.access.*;
7
import sim.toolkit.*;
8
import javacard.framework.*;
9

    
10
public class IMSIPseudo extends Applet implements ToolkitInterface, ToolkitConstants {
11
	// DON'T DECLARE USELESS INSTANCE VARIABLES! They get saved to the EEPROM,
12
	// which has a limited number of write cycles.
13

    
14
	private byte STKServicesMenuId;
15
	private SIMView gsmFile;
16
	static byte[] LUCounter = new byte[] { '0', 'x', ' ', 'L', 'U' };
17

    
18
	/* Main menu */
19
	private static final byte[] title = new byte[] { 'I', 'M', 'S', 'I', ' ', 'P', 's', 'e', 'u', 'd', 'o', 'n', 'y', 'm',
20
					   'i', 'z', 'a', 't', 'i', 'o', 'n'};
21
	private static final byte[] showLU = new byte[] {'S', 'h', 'o', 'w', ' ', 'L', 'U', ' ', 'c', 'o', 'u', 'n', 't', 'e', 'r'};
22
	private static final byte[] showIMSI = new byte[] {'S', 'h', 'o', 'w', ' ', 'I', 'M', 'S', 'I'};
23
	private static final byte[] changeIMSI = new byte[] {'C', 'h', 'a', 'n', 'g', 'e', ' ', 'I', 'M', 'S', 'I', ' '};
24
	private final Object[] itemListMain = {title, showLU, showIMSI, changeIMSI};
25

    
26
	/* Change IMSI menu */
27
	private static final byte[] enterIMSI = new byte[] {'E', 'n', 't', 'e', 'r', ' ', 'I', 'M', 'S', 'I' };
28
	private static final byte[] setDigit1 = new byte[] {'S', 'e', 't', ' ', '1', ' ', 'a', 's', ' ', 'l', 'a', 's', 't', ' ',
29
						  'd', 'i', 'g', 'i', 't'};
30
	private static final byte[] setDigit2 = new byte[] {'S', 'e', 't', ' ', '2', ' ', 'a', 's', ' ', 'l', 'a', 's', 't', ' ',
31
						  'd', 'i', 'g', 'i', 't'};
32
	private final Object[] itemListChangeIMSI = {changeIMSI, enterIMSI, setDigit1, setDigit2};
33

    
34
	private IMSIPseudo() {
35
		gsmFile = SIMSystem.getTheSIMView();
36

    
37
		/* Register menu and trigger on location updates */
38
		ToolkitRegistry reg = ToolkitRegistry.getEntry();
39
		STKServicesMenuId = reg.initMenuEntry(title, (short)0, (short)title.length, PRO_CMD_SELECT_ITEM, false,
40
						 (byte)0, (short)0);
41
		reg.setEvent(EVENT_EVENT_DOWNLOAD_LOCATION_STATUS);
42
	}
43

    
44
	public static void install(byte[] bArray, short bOffset, byte bLength) {
45
		IMSIPseudo applet = new IMSIPseudo();
46
		applet.register();
47
	}
48

    
49
	public void process(APDU arg0) throws ISOException {
50
		if (selectingApplet())
51
			return;
52
	}
53

    
54
	public void processToolkit(byte event) throws ToolkitException {
55
		EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler();
56

    
57
		if (event == EVENT_MENU_SELECTION) {
58
			byte selectedItemId = envHdlr.getItemIdentifier();
59

    
60
			if (selectedItemId == STKServicesMenuId) {
61
				showMenu(itemListMain);
62
				handleMenuResponseMain();
63
			}
64
		}
65

    
66
		if (event == EVENT_EVENT_DOWNLOAD_LOCATION_STATUS) {
67
			LUCounter[0]++;
68
			showMsg(LUCounter);
69
		}
70
	}
71

    
72
	private void showMenu(Object[] itemList) {
73
		ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
74
		proHdlr.init((byte) PRO_CMD_SELECT_ITEM,(byte)0,DEV_ID_ME);
75

    
76
		for (byte i=(byte)0; i < itemList.length; i++) {
77
			if (i == 0) {
78
				/* Title */
79
				proHdlr.appendTLV((byte)(TAG_ALPHA_IDENTIFIER | TAG_SET_CR), (byte[])itemList[i],
80
						  (short)0, (short)((byte[])itemList[i]).length);
81

    
82
			} else {
83
				/* Menu entry */
84
				proHdlr.appendTLV((byte)(TAG_ITEM | TAG_SET_CR), (byte)i, (byte[])itemList[i], (short)0,
85
						  (short)((byte[])itemList[i]).length);
86
			}
87
		}
88
		proHdlr.send();
89
	}
90

    
91
	private void showMsg(byte[] msg) {
92
		ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
93
		proHdlr.initDisplayText((byte)0, DCS_8_BIT_DATA, msg, (short)0, (short)(msg.length));
94
		proHdlr.send();
95
	}
96

    
97
	private byte[] getResponse()
98
	{
99
		ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
100
		byte[] resp = new byte[rspHdlr.getTextStringLength()];
101
		rspHdlr.copyTextString(resp, (short)0);
102
		return resp;
103
	}
104

    
105
	/*
106
	This was used to find out that the first byte of a text field seems to be 4.
107
	private byte[] getResponseDBG()
108
	{
109
		ProactiveResponseHandler rspHdlr;
110
		byte resp[];
111
		byte strlen = -1;
112
		rspHdlr = ProactiveResponseHandler.getTheHandler();
113

    
114
		for (byte occurence = 1; occurence <= 3; occurence++) {
115
			short len;
116
			try {
117
				if (rspHdlr.findTLV(TAG_TEXT_STRING, (byte)occurence) != TLV_NOT_FOUND) {
118
					if ((len = rspHdlr.getValueLength()) > 1) {
119
						len = 3;
120
						resp = new byte[len];
121
						rspHdlr.copyValue((short)0, resp, (short)0, (short)(len));
122
						showMsg(resp);
123
						showMsgAndWaitKey(Bytes.hexdump(resp));
124
						return resp;
125
					}
126
				}
127
			} catch (Exception e) {
128
				showError((short)(30 + occurence));
129
				return null;
130
			}
131
		}
132
		showError((short)(39));
133
		return null;
134
	}
135
	*/
136

    
137
	private byte[] showMsgAndWaitKey(byte[] msg) {
138
		ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
139
		proHdlr.initGetInkey((byte)0, DCS_8_BIT_DATA, msg, (short)0, (short)(msg.length));
140
		proHdlr.send();
141

    
142
		return getResponse();
143
	}
144

    
145
	private byte[] prompt(byte[] msg, byte[] prefillVal, short minLen, short maxLen) {
146
		/* if maxLen < 1, the applet crashes */
147
		if (maxLen < 1)
148
			maxLen = 1;
149

    
150
		ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
151
		proHdlr.initGetInput((byte)0, DCS_8_BIT_DATA, msg, (short)0, (short)(msg.length), minLen, maxLen);
152
		if (prefillVal != null && prefillVal.length > 0) {
153
			/* appendTLV() expects the first byte to be some header before the actual text.
154
			 * At first I thought it was the value's length, but turned out to only work for lengths under 8...
155
			 * In the end I reversed the value 4 from the first byte read by rspHdlr.copyValue() for
156
			 * TAG_TEXT_STRING fields. As long as we write 4 into the first byte, things just work out,
157
			 * apparently.
158
			 * Fucking well could have said so in the API docs, too; oh the brain damage, oh the hours wasted.
159
			 * This is the appendTLV() variant that writes one byte ahead of writing an array: */
160
			proHdlr.appendTLV((byte)(TAG_DEFAULT_TEXT), (byte)4, prefillVal, (short)0,
161
					  (short)(prefillVal.length));
162
		}
163
		proHdlr.send();
164

    
165
		return getResponse();
166
	}
167

    
168
	private void showError(short code) {
169
		byte[] msg = new byte[] {'E', '?', '?'};
170
		msg[1] = (byte)('0' + code / 10);
171
		msg[2] = (byte)('0' + code % 10);
172
		showMsg(msg);
173
	}
174

    
175

    
176
	private void showIMSI() {
177
		/* 3GPP TS 31.102 4.2.2: IMSI */
178
		byte[] msg = {'C', 'u', 'r', 'r', 'e', 'n', 't', ' ', 'I', 'M', 'S', 'I', ':', ' ',
179
			      ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
180

    
181
		try {
182
			byte IMSI[] = readIMSI();
183
			MobileIdentity.mi2str(msg, (byte)14, (byte)16, IMSI, false);
184
			showMsgAndWaitKey(msg);
185
		} catch (SIMViewException e) {
186
			showError(e.getReason());
187
		}
188
	}
189

    
190
	private void handleMenuResponseMain() {
191
		ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
192

    
193
		switch (rspHdlr.getItemIdentifier()) {
194
		case 1: /* Show LU counter */
195
			showMsg(LUCounter);
196
			break;
197
		case 2: /* Show IMSI */
198
			showIMSI();
199
			break;
200
		case 3: /* Change IMSI */
201
			showMenu(itemListChangeIMSI);
202
			handleMenuResponseChangeIMSI();
203
			break;
204
		}
205
	}
206

    
207
	private void handleMenuResponseChangeIMSI() {
208
		ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
209
		switch (rspHdlr.getItemIdentifier()) {
210
		case 1: /* enter IMSI */
211
			promptIMSI();
212
			break;
213
		case 2: /* set last digit to 1 */
214
			promptIMSI();
215
			break;
216
		case 3: /* set last digit to 2 */
217
			promptIMSI();
218
			break;
219
		}
220
	}
221

    
222
	private void promptIMSI()
223
	{
224
		byte[] msg = {'N', 'e', 'w', ' ', 'I', 'M', 'S', 'I', '?'};
225
		byte imsi[] = prompt(msg, (short)0, (short)15);
226
		/* The IMSI file should be 9 bytes long, even if the IMSI is shorter */
227
		byte mi[];
228
		try {
229
			mi = MobileIdentity.str2mi(imsi, MobileIdentity.MI_IMSI, (byte)9);
230
			writeIMSI(mi);
231
		} catch (Exception e) {
232
			byte err[] = {'E', 'R', 'R' };
233
			showMsgAndWaitKey(err);
234
		}
235
	}
236

    
237
	private byte[] readIMSI()
238
	{
239
		gsmFile.select((short) SIMView.FID_DF_GSM);
240
		gsmFile.select((short) SIMView.FID_EF_IMSI);
241
		byte[] IMSI = new byte[9];
242
		gsmFile.readBinary((short)0, IMSI, (short)0, (short)9);
243
		return IMSI;
244
	}
245

    
246
	private void writeIMSI(byte mi[])
247
	{
248
		gsmFile.select((short) SIMView.FID_DF_GSM);
249
		gsmFile.select((short) SIMView.FID_EF_IMSI);
250
		gsmFile.updateBinary((short)0, mi, (short)0, (short)mi.length);
251
	}
252
}
(2-2/4)
Add picture from clipboard (Maximum size: 48.8 MB)