Project

General

Profile

Download (6.89 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, (byte)4);
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, byte itemCount) {
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<itemCount;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
	private byte[] showMsgAndWaitKey(byte[] msg) {
106
		ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
107
		proHdlr.initGetInkey((byte)0, DCS_8_BIT_DATA, msg, (short)0, (short)(msg.length));
108
		proHdlr.send();
109

    
110
		return getResponse();
111
	}
112

    
113
	private byte[] prompt(byte[] msg, short minLen, short maxLen) {
114
		/* if maxLen < 1, the applet crashes */
115
		if (maxLen < 1)
116
			maxLen = 1;
117

    
118
		ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
119
		proHdlr.initGetInput((byte)0, DCS_8_BIT_DATA, msg, (short)0, (short)(msg.length), minLen, maxLen);
120
		proHdlr.send();
121

    
122
		return getResponse();
123
	}
124

    
125
	private void showError(short code) {
126
		byte[] msg = new byte[] {'E', '?', '?'};
127
		msg[1] = (byte)('0' + code / 10);
128
		msg[2] = (byte)('0' + code % 10);
129
		showMsg(msg);
130
	}
131

    
132
	private byte nibble2hex(byte nibble)
133
	{
134
		nibble = (byte)(nibble & 0xf);
135
		if (nibble < 0xa)
136
			return (byte)('0' + nibble);
137
		else
138
			return (byte)('a' + nibble - 0xa);
139
	}
140

    
141
	private byte[] hexdump(byte data[])
142
	{
143
		byte res[] = new byte[(byte)(data.length*2)];
144
		for (byte i = 0; i < data.length; i++) {
145
			res[(byte)(i*2)] = nibble2hex((byte)(data[i] >> 4));
146
			res[(byte)(i*2 + 1)] = nibble2hex(data[i]);
147
		}
148
		return res;
149
	}
150

    
151
	private void showIMSI() {
152
		/* 3GPP TS 31.102 4.2.2: IMSI */
153
		byte[] msg = {'C', 'u', 'r', 'r', 'e', 'n', 't', ' ', 'I', 'M', 'S', 'I', ':', ' ',
154
			      ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
155

    
156
		try {
157
			byte IMSI[] = readIMSI();
158
			MobileIdentity.mi2str(msg, (byte)14, (byte)16, IMSI, false);
159
			showMsgAndWaitKey(msg);
160
		} catch (SIMViewException e) {
161
			showError(e.getReason());
162
		}
163
	}
164

    
165
	private void handleMenuResponseMain() {
166
		ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
167

    
168
		switch (rspHdlr.getItemIdentifier()) {
169
		case 1: /* Show LU counter */
170
			showMsg(LUCounter);
171
			break;
172
		case 2: /* Show IMSI */
173
			showIMSI();
174
			break;
175
		case 3: /* Change IMSI */
176
			showMenu(itemListChangeIMSI, (byte)4);
177
			handleMenuResponseChangeIMSI();
178
			break;
179
		}
180
	}
181

    
182
	private void handleMenuResponseChangeIMSI() {
183
		ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
184
		switch (rspHdlr.getItemIdentifier()) {
185
		case 1: /* enter IMSI */
186
			promptIMSI();
187
			break;
188
		case 2: /* set last digit to 1 */
189
			promptIMSI();
190
			break;
191
		case 3: /* set last digit to 2 */
192
			promptIMSI();
193
			break;
194
		}
195
	}
196

    
197
	private void promptIMSI()
198
	{
199
		byte[] msg = {'N', 'e', 'w', ' ', 'I', 'M', 'S', 'I', '?'};
200
		byte imsi[] = prompt(msg, (short)0, (short)15);
201
		/* The IMSI file should be 9 bytes long, even if the IMSI is shorter */
202
		byte mi[];
203
		try {
204
			mi = MobileIdentity.str2mi(imsi, MobileIdentity.MI_IMSI, (byte)9);
205
			showMsgAndWaitKey(hexdump(mi));
206
		} catch (Exception e) {
207
			byte err[] = {'E', 'R', 'R' };
208
			showMsgAndWaitKey(err);
209
		}
210
	}
211

    
212
	private byte[] readIMSI()
213
	{
214
		gsmFile.select((short) SIMView.FID_DF_GSM);
215
		gsmFile.select((short) SIMView.FID_EF_IMSI);
216
		byte[] IMSI = new byte[9];
217
		gsmFile.readBinary((short)0, IMSI, (short)0, (short)9);
218
		return IMSI;
219
	}
220

    
221
	private void writeIMSI(byte mi[])
222
	{
223
		gsmFile.select((short) SIMView.FID_DF_GSM);
224
		gsmFile.select((short) SIMView.FID_EF_IMSI);
225
		gsmFile.updateBinary((short)0, mi, (short)0, (short)mi.length);
226
	}
227
}
(1-1/3)
Add picture from clipboard (Maximum size: 48.8 MB)