blob: 8a94c8a9c1efb63789d5fce9611a4ca379acb6ef [file] [log] [blame]
Kévin Redon45ad62d2018-06-07 18:56:41 +02001/*
2 * (C) 2010-2017 by Harald Welte <hwelte@sysmocom.de>
3 * (C) 2018 by Kevin Redon <kredon@sysmocom.de>
4 * All Rights Reserved
Christina Quasta90eefa2015-02-24 17:52:29 +01005 *
Kévin Redon45ad62d2018-06-07 18:56:41 +02006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
Christina Quasta90eefa2015-02-24 17:52:29 +010010 *
Kévin Redon45ad62d2018-06-07 18:56:41 +020011 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
Christina Quasta90eefa2015-02-24 17:52:29 +010015 *
Kévin Redon45ad62d2018-06-07 18:56:41 +020016 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Christina Quasta90eefa2015-02-24 17:52:29 +010018 *
Christina Quasta90eefa2015-02-24 17:52:29 +010019 */
Kévin Redon8fa6ff52018-06-25 16:00:33 +020020/* This code implement the Sniffer mode to sniff the communication between a SIM card (or any ISO 7816 smart card) and a phone (or any ISO 7816 card reader).
Kévin Redond7a6de52018-06-11 13:46:35 +020021 * For historical reasons (i.e. SIMtrace hardware) the USART peripheral connected to the SIM card is used.
Kévin Redon8fa6ff52018-06-25 16:00:33 +020022 * TODO handle RST, PTS, and send data over USB
23 * TODO put common ISO7816-3 code is separate library (and combine clean with iso7816_4)
Kévin Redond7a6de52018-06-11 13:46:35 +020024 */
Kévin Redon36abece2018-06-04 16:30:01 +020025#include "board.h"
26#include "simtrace.h"
27
Harald Welte2fb59962016-02-28 12:34:26 +010028#ifdef HAVE_SNIFFER
29
Christina Quasta90eefa2015-02-24 17:52:29 +010030/*------------------------------------------------------------------------------
31 * Headers
32 *------------------------------------------------------------------------------*/
33
Christina Quasta90eefa2015-02-24 17:52:29 +010034#include <string.h>
Kévin Redon8fa6ff52018-06-25 16:00:33 +020035#include "utils.h"
36#include "iso7816_fidi.h"
Christina Quasta90eefa2015-02-24 17:52:29 +010037
38/*------------------------------------------------------------------------------
39 * Internal definitions
40 *------------------------------------------------------------------------------*/
41
Kévin Redon8fa6ff52018-06-25 16:00:33 +020042/*! Maximum Answer-To-Reset (ATR) size in bytes
Kévin Redond7a6de52018-06-11 13:46:35 +020043 * @note defined in ISO/IEC 7816-3:2006(E) section 8.2.1 as 32, on top the initial character TS of section 8.1
44 * @remark technical there is no size limitation since Yi present in T0,TDi will indicate if more interface bytes are present, including TDi+i
45 */
46#define MAX_ATR_SIZE 33
Kévin Redon8fa6ff52018-06-25 16:00:33 +020047/*! Maximum Protocol and Parameters Selection (PPS) size in bytes
48 * @note defined in ISO/IEC 7816-3:2006(E) section 9.2
49 */
50#define MAX_PPS_SIZE 6
Kévin Redond7a6de52018-06-11 13:46:35 +020051
52/*! ISO 7816-3 states relevant to the sniff mode */
53enum iso7816_3_sniff_state {
54 ISO7816_S_RESET, /*!< in Reset */
55 ISO7816_S_WAIT_ATR, /*!< waiting for ATR to start */
56 ISO7816_S_IN_ATR, /*!< while we are receiving the ATR */
Kévin Redon00ec89d2018-06-27 16:41:52 +020057 ISO7816_S_WAIT_TPDU, /*!< waiting for start of new TPDU */
58 ISO7816_S_IN_TPDU, /*!< inside a single TPDU */
Kévin Redon8fa6ff52018-06-25 16:00:33 +020059 ISO7816_S_IN_PPS_REQ, /*!< while we are inside the PPS request */
60 ISO7816_S_WAIT_PPS_RSP, /*!< waiting for start of the PPS response */
61 ISO7816_S_IN_PPS_RSP, /*!< while we are inside the PPS request */
Kévin Redond7a6de52018-06-11 13:46:35 +020062};
63
64/*! Answer-To-Reset (ATR) sub-states of ISO7816_S_IN_ATR
65 * @note defined in ISO/IEC 7816-3:2006(E) section 8
66 */
67enum atr_sniff_state {
68 ATR_S_WAIT_TS, /*!< initial byte */
69 ATR_S_WAIT_T0, /*!< format byte */
70 ATR_S_WAIT_TA, /*!< first sub-group interface byte */
71 ATR_S_WAIT_TB, /*!< second sub-group interface byte */
72 ATR_S_WAIT_TC, /*!< third sub-group interface byte */
73 ATR_S_WAIT_TD, /*!< fourth sub-group interface byte */
74 ATR_S_WAIT_HIST, /*!< historical byte */
75 ATR_S_WAIT_TCK, /*!< check byte */
Kévin Redon8fa6ff52018-06-25 16:00:33 +020076};
77
78/*! Protocol and Parameters Selection (PPS) sub-states of ISO7816_S_IN_PTS_REQ/ISO7816_S_IN_PTS_RSP
79 * @note defined in ISO/IEC 7816-3:2006(E) section 9
80 */
81enum pps_sniff_state {
82 PPS_S_WAIT_PPSS, /*!< initial byte */
83 PPS_S_WAIT_PPS0, /*!< format byte */
84 PPS_S_WAIT_PPS1, /*!< first parameter byte */
85 PPS_S_WAIT_PPS2, /*!< second parameter byte */
86 PPS_S_WAIT_PPS3, /*!< third parameter byte */
87 PPS_S_WAIT_PCK, /*!< check byte */
Kévin Redond7a6de52018-06-11 13:46:35 +020088};
Kévin Redon45ad62d2018-06-07 18:56:41 +020089
Kévin Redon00ec89d2018-06-27 16:41:52 +020090/*! Transport Protocol Data Unit (TPDU) sub-states of ISO7816_S_IN_TPDU
91 * @note defined in ISO/IEC 7816-3:2006(E) section 10 and 12
92 * @remark APDUs are formed by one or more command+response TPDUs
93 */
94enum tpdu_sniff_state {
95 TPDU_S_CLA, /*!< class byte */
96 TPDU_S_INS, /*!< instruction byte */
97 TPDU_S_P1, /*!< first parameter byte for the instruction */
98 TPDU_S_P2, /*!< second parameter byte for the instruction */
99 TPDU_S_P3, /*!< third parameter byte encoding the data length */
100 TPDU_S_PROCEDURE, /*!< procedure byte (could also be SW1) */
101 TPDU_S_DATA_REMAINING, /*!< remaining data bytes */
102 TPDU_S_DATA_SINGLE, /*!< single data byte */
103 TPDU_S_SW1, /*!< first status word */
104 TPDU_S_SW2, /*!< second status word */
105};
106
Christina Quasta90eefa2015-02-24 17:52:29 +0100107/*------------------------------------------------------------------------------
108 * Internal variables
109 *------------------------------------------------------------------------------*/
Kévin Redond7a6de52018-06-11 13:46:35 +0200110
111/* note: the sniffer code is currently designed to support only one sniffing interface, but the hardware would support a second one.
112 * to support a second sniffer interface the code should be restructured to use handles.
113 */
114/* Pin configurations */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200115/*! Pin configuration to sniff communication (using USART connection card) */
Kévin Redonee62a9d2018-06-11 13:42:23 +0200116static const Pin pins_sniff[] = { PINS_SIM_SNIFF };
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200117/*! Pin configuration to interconnect phone and card using the bus switch */
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100118static const Pin pins_bus[] = { PINS_BUS_SNIFF };
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200119/*! Pin configuration to power the card by the phone */
Kévin Redond7a6de52018-06-11 13:46:35 +0200120static const Pin pins_power[] = { PINS_PWR_SNIFF };
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200121/*! Pin configuration for timer counter to measure ETU timing */
Kévin Redon45ad62d2018-06-07 18:56:41 +0200122static const Pin pins_tc[] = { PINS_TC };
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200123/*! Pin configuration for card reset line */
124static const Pin pin_rst = PIN_SIM_RST_SNIFF;
125
Kévin Redond7a6de52018-06-11 13:46:35 +0200126/* USART related variables */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200127/*! USART peripheral used to sniff communication */
Kévin Redon45ad62d2018-06-07 18:56:41 +0200128static struct Usart_info sniff_usart = {
129 .base = USART_SIM,
130 .id = ID_USART_SIM,
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100131 .state = USART_RCV,
132};
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200133/*! Ring buffer to store sniffer communication data */
Kévin Redon7b734622018-06-06 16:13:48 +0200134static struct ringbuf sniff_buffer;
135
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200136/* ISO 7816 variables */
137/*! ISO 7816-3 state */
138enum iso7816_3_sniff_state iso_state = ISO7816_S_RESET;
139/*! ATR state */
140enum atr_sniff_state atr_state;
141/*! ATR data
142 * @remark can be used to check later protocol changes
143 */
144uint8_t atr[MAX_ATR_SIZE];
145/*! Current index in the ATR data */
146uint8_t atr_i = 0;
147/*! If convention conversion is needed */
148bool convention_convert = false;
149/*! The supported T protocols */
150uint16_t t_protocol_support = 0;
151/*! PPS state
152 * @remark it is shared between request and response since they aren't simultaneous but follow the same procedure
153 */
154enum pps_sniff_state pps_state;
155/*! PPS request data
156 * @remark can be used to check PPS response
157 */
158uint8_t pps_req[MAX_PPS_SIZE];
159/*! PPS response data */
160uint8_t pps_rsp[MAX_PPS_SIZE];
Kévin Redon00ec89d2018-06-27 16:41:52 +0200161/*! TPDU state */
162enum tpdu_sniff_state tpdu_state;
163/*! Final TPDU packet
164 * @note this is the complete command+response TPDU, including header, data, and status words
165 * @remark this does not include the procedure bytes
166 */
167uint8_t tpdu_packet[5+256+2];
168/*! Current index in TPDU packet */
169uint8_t tpdu_packet_i = 0;
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200170
Kévin Redon7b734622018-06-06 16:13:48 +0200171/*------------------------------------------------------------------------------
Kévin Redon7b734622018-06-06 16:13:48 +0200172 * Internal functions
173 *------------------------------------------------------------------------------*/
Kévin Redon36abece2018-06-04 16:30:01 +0200174
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200175/*! Convert data between direct and inverse convention
176 * @note direct convention is LSb first and HIGH=1; inverse conversion in MSb first and LOW=1
177 * @remark use a look up table to speed up conversion
178 */
179static const uint8_t convention_convert_lut[256] = { 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f, 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f, 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17, 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07, 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b, 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b, 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13, 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03, 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d, 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d, 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15, 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05, 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19, 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09, 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11, 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01, 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e, 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e, 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16, 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06, 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a, 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a, 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12, 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02, 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c, 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c, 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14, 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04, 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18, 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08, 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10, 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00, };
180
181/*! Update the ISO 7816-3 state
182 * @param[in] iso_state_new new ISO 7816-3 state to update to
183 */
184static void change_state(enum iso7816_3_sniff_state iso_state_new)
185{
186 /* sanity check */
187 if (iso_state_new==iso_state) {
188 TRACE_WARNING("Already in ISO 7816 state %u\n\r", iso_state);
189 return;
190 }
191
192 /* handle actions to perform when switching state */
193 switch (iso_state_new) {
194 case ISO7816_S_RESET:
195 update_fidi(&sniff_usart, 0x11); /* reset baud rate to default Di/Fi values */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200196 break;
197 case ISO7816_S_WAIT_ATR:
198 rbuf_reset(&sniff_buffer); /* reset buffer for new communication */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200199 break;
200 case ISO7816_S_IN_ATR:
201 atr_i = 0;
202 convention_convert = false;
203 t_protocol_support = 0;
204 atr_state = ATR_S_WAIT_TS;
205 break;
206 case ISO7816_S_IN_PPS_REQ:
207 case ISO7816_S_IN_PPS_RSP:
208 pps_state = PPS_S_WAIT_PPSS;
209 break;
Kévin Redon00ec89d2018-06-27 16:41:52 +0200210 case ISO7816_S_WAIT_TPDU:
211 tpdu_state = TPDU_S_CLA;
212 tpdu_packet_i = 0;
213 break;
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200214 default:
215 break;
216 }
217
218 /* save new state */
219 iso_state = iso_state_new;
Kévin Redoncf599192018-06-27 16:38:31 +0200220 //TRACE_INFO("Changed to ISO 7816-3 state %u\n\r", iso_state); /* don't print since this is function is also called by ISRs */
221}
222
223/*! Print current ATR */
224static void print_atr(void)
225{
226 if (ISO7816_S_IN_ATR!=iso_state) {
227 TRACE_WARNING("Can't print ATR in ISO 7816-3 state %u\n\r", iso_state);
228 return;
229 }
230
231 led_blink(LED_GREEN, BLINK_2O_F);
232 printf("ATR: ");
233 uint8_t i;
234 for (i = 0; i < atr_i && i < ARRAY_SIZE(atr); i++) {
235 printf("%02x ", atr[i]);
236 }
237 printf("\n\r");
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200238}
239
240/*! Process ATR byte
241 * @param[in] byte ATR byte to process
242 */
243static void process_byte_atr(uint8_t byte)
244{
245 static uint8_t atr_hist_len = 0; /* store the number of expected historical bytes */
246 static uint8_t y = 0; /* last mask of the upcoming TA, TB, TC, TD interface bytes */
247
248 /* sanity check */
249 if (ISO7816_S_IN_ATR!=iso_state) {
250 TRACE_ERROR("Processing ATR data in wrong ISO 7816-3 state %u\n\r", iso_state);
251 return;
252 }
253 if (atr_i>=ARRAY_SIZE(atr)) {
Kévin Redoncf599192018-06-27 16:38:31 +0200254 TRACE_ERROR("ATR data overflow\n\r");
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200255 return;
256 }
257
258 /* save data for use by other functions */
259 atr[atr_i++] = byte;
260
261 /* handle ATR byte depending on current state */
262 switch (atr_state) {
263 case ATR_S_WAIT_TS: /* see ISO/IEC 7816-3:2006 section 8.1 */
264 switch (byte) {
265 case 0x23: /* direct convention used, but decoded using inverse convention (a parity error should also have occurred) */
266 case 0x30: /* inverse convention used, but decoded using direct convention (a parity error should also have occurred) */
267 convention_convert = !convention_convert;
268 case 0x3b: /* direct convention used and correctly decoded */
269 case 0x3f: /* inverse convention used and correctly decoded */
270 atr_state = ATR_S_WAIT_T0; /* wait for format byte */
271 break;
272 default:
273 atr_i--; /* revert last byte */
274 TRACE_WARNING("Invalid TS received\n\r");
275 }
276 break;
277 case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
278 case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
279 if (ATR_S_WAIT_T0==atr_state) {
280 atr_hist_len = (byte&0x0f); /* save the number of historical bytes */
281 } else if (ATR_S_WAIT_TD==atr_state) {
282 t_protocol_support |= (1<<(byte&0x0f)); /* remember supported protocol to know if TCK will be present */
283 }
284 y = (byte&0xf0); /* remember upcoming interface bytes */
285 if (y&0x10) {
286 atr_state = ATR_S_WAIT_TA; /* wait for interface byte TA */
287 break;
288 }
289 case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
290 if (y&0x20) {
291 atr_state = ATR_S_WAIT_TB; /* wait for interface byte TB */
292 break;
293 }
294 case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
295 if (y&0x40) {
296 atr_state = ATR_S_WAIT_TC; /* wait for interface byte TC */
297 break;
298 }
299 case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
300 if (y&0x80) {
301 atr_state = ATR_S_WAIT_TD; /* wait for interface byte TD */
302 break;
303 } else if (atr_hist_len) {
304 atr_state = ATR_S_WAIT_HIST; /* wait for historical bytes */
305 break;
306 }
307 case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */
308 if (atr_hist_len) {
309 atr_hist_len--;
310 }
311 if (0==atr_hist_len) {
312 if (t_protocol_support>1) {
313 atr_state = ATR_S_WAIT_TCK; /* wait for check bytes */
314 break;
315 }
316 } else {
317 break;
318 }
319 case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
320 /* we could verify the checksum, but we are just here to sniff */
Kévin Redoncf599192018-06-27 16:38:31 +0200321 print_atr(); /* print ATR for info */
Kévin Redon00ec89d2018-06-27 16:41:52 +0200322 change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200323 break;
324 default:
325 TRACE_INFO("Unknown ATR state %u\n\r", atr_state);
326 }
327}
328
Kévin Redoncf599192018-06-27 16:38:31 +0200329/*! Print current PPS */
330static void print_pps(void)
331{
332 uint8_t *pps_cur; /* current PPS (request or response) */
333
334 /* sanity check */
335 if (ISO7816_S_IN_PPS_REQ==iso_state) {
336 pps_cur = pps_req;
337 } else if (ISO7816_S_IN_PPS_RSP==iso_state) {
338 pps_cur = pps_rsp;
339 } else {
340 TRACE_ERROR("Can't print PPS in ISO 7816-3 state %u\n\r", iso_state);
341 return;
342 }
343
344 led_blink(LED_GREEN, BLINK_2O_F);
345 printf("PPS %s : ", ISO7816_S_IN_PPS_REQ==iso_state ? "REQUEST" : "RESPONSE");
346 printf("%02x ", pps_cur[0]);
347 printf("%02x ", pps_cur[1]);
348 if (pps_cur[1]&0x10) {
349 printf("%02x ", pps_cur[2]);
350 }
351 if (pps_cur[1]&0x20) {
352 printf("%02x ", pps_cur[3]);
353 }
354 if (pps_cur[1]&0x40) {
355 printf("%02x ", pps_cur[4]);
356 }
357 printf("%02x ", pps_cur[5]);
358 printf("\n\r");
359}
360
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200361static void process_byte_pps(uint8_t byte)
362{
363 uint8_t *pps_cur; /* current PPS (request or response) */
364
365 /* sanity check */
366 if (ISO7816_S_IN_PPS_REQ==iso_state) {
367 pps_cur = pps_req;
368 } else if (ISO7816_S_IN_PPS_RSP==iso_state) {
369 pps_cur = pps_rsp;
370 } else {
371 TRACE_ERROR("Processing PPS data in wrong ISO 7816-3 state %u\n\r", iso_state);
372 return;
373 }
374
375 /* handle PPS byte depending on current state */
376 switch (pps_state) { /* see ISO/IEC 7816-3:2006 section 9.2 */
377 case PPS_S_WAIT_PPSS: /*!< initial byte */
378 if (0xff) {
379 pps_cur[0] = byte;
380 pps_state = PPS_S_WAIT_PPS0; /* go to next state */
381 } else {
382 TRACE_INFO("Invalid PPSS received\n\r");
Kévin Redon00ec89d2018-06-27 16:41:52 +0200383 change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200384 }
385 break;
386 case PPS_S_WAIT_PPS0: /*!< format byte */
387 pps_cur[1] = byte;
388 if (pps_cur[1]&0x10) {
389 pps_state = PPS_S_WAIT_PPS1; /* go to next state */
390 break;
391 }
392 case PPS_S_WAIT_PPS1: /*!< first parameter byte */
393 pps_cur[2] = byte; /* not always right but doesn't affect the process */
394 if (pps_cur[1]&0x20) {
395 pps_state = PPS_S_WAIT_PPS2; /* go to next state */
396 break;
397 }
398 case PPS_S_WAIT_PPS2: /*!< second parameter byte */
399 pps_cur[3] = byte; /* not always right but doesn't affect the process */
400 if (pps_cur[1]&0x40) {
401 pps_state = PPS_S_WAIT_PPS3; /* go to next state */
402 break;
403 }
404 case PPS_S_WAIT_PPS3: /*!< third parameter byte */
405 pps_cur[4] = byte; /* not always right but doesn't affect the process */
406 pps_state = PPS_S_WAIT_PCK; /* go to next state */
407 break;
408 case PPS_S_WAIT_PCK: /*!< check byte */
409 pps_cur[5] = byte; /* not always right but doesn't affect the process */
410 /* verify the checksum */
411 uint8_t check = 0;
412 check ^= pps_cur[0];
413 check ^= pps_cur[1];
414 if (pps_cur[1]&0x10) {
415 check ^= pps_cur[2];
416 }
417 if (pps_cur[1]&0x20) {
418 check ^= pps_cur[3];
419 }
420 if (pps_cur[1]&0x40) {
421 check ^= pps_cur[4];
422 }
423 check ^= pps_cur[5];
Kévin Redoncf599192018-06-27 16:38:31 +0200424 print_pps(); /* print PPS for info */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200425 if (ISO7816_S_IN_PPS_REQ==iso_state) {
426 if (0==check) { /* checksum is valid */
427 change_state(ISO7816_S_WAIT_PPS_RSP); /* go to next state */
428 } else { /* checksum is invalid */
Kévin Redon00ec89d2018-06-27 16:41:52 +0200429 change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200430 }
431 } else if (ISO7816_S_IN_PPS_RSP==iso_state) {
432 if (0==check) { /* checksum is valid */
433 uint8_t fn, dn;
434 if (pps_cur[1]&0x10) {
435 fn = (pps_cur[2]>>4);
436 dn = (pps_cur[2]&0x0f);
437 } else {
438 fn = 1;
439 dn = 1;
440 }
441 TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r", fn, dn);
442 update_fidi(&sniff_usart, pps_cur[2]);
443 } else { /* checksum is invalid */
444 TRACE_INFO("PPS negotiation failed\n\r");
445 }
Kévin Redon00ec89d2018-06-27 16:41:52 +0200446 change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200447 }
448 break;
449 default:
450 TRACE_INFO("Unknown PPS state %u\n\r", pps_state);
451 }
452}
453
Kévin Redon00ec89d2018-06-27 16:41:52 +0200454/*! Print current TPDU */
455static void print_tpdu(void)
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200456{
Kévin Redon00ec89d2018-06-27 16:41:52 +0200457 if (ISO7816_S_IN_TPDU!=iso_state) {
458 TRACE_WARNING("Can't print TPDU in ISO 7816-3 state %u\n\r", iso_state);
459 return;
460 }
461
462 led_blink(LED_GREEN, BLINK_2O_F);
463 printf("TPDU: ");
464 uint16_t i;
465 for (i = 0; i < tpdu_packet_i && i < ARRAY_SIZE(tpdu_packet); i++) {
466 printf("%02x ", tpdu_packet[i]);
467 }
468 printf("\n\r");
469}
470
471static void process_byte_tpdu(uint8_t byte)
472{
473 /* sanity check */
474 if (ISO7816_S_IN_TPDU!=iso_state) {
475 TRACE_ERROR("Processing TPDU data in wrong ISO 7816-3 state %u\n\r", iso_state);
476 return;
477 }
478 if (tpdu_packet_i>=ARRAY_SIZE(tpdu_packet)) {
479 TRACE_ERROR("TPDU data overflow\n\r");
480 return;
481 }
482
483 /* handle TPDU byte depending on current state */
484 switch (tpdu_state) {
485 case TPDU_S_CLA:
486 if (0xff==byte) {
487 TRACE_WARNING("0xff is not a valid class byte\n\r");
488 break;
489 }
490 tpdu_packet_i = 0;
491 tpdu_packet[tpdu_packet_i++] = byte;
492 tpdu_state = TPDU_S_INS;
493 break;
494 case TPDU_S_INS:
495 tpdu_packet_i = 1;
496 tpdu_packet[tpdu_packet_i++] = byte;
497 tpdu_state = TPDU_S_P1;
498 break;
499 case TPDU_S_P1:
500 tpdu_packet_i = 2;
501 tpdu_packet[tpdu_packet_i++] = byte;
502 tpdu_state = TPDU_S_P2;
503 break;
504 case TPDU_S_P2:
505 tpdu_packet_i = 3;
506 tpdu_packet[tpdu_packet_i++] = byte;
507 tpdu_state = TPDU_S_P3;
508 break;
509 case TPDU_S_P3:
510 tpdu_packet_i = 4;
511 tpdu_packet[tpdu_packet_i++] = byte;
512 tpdu_state = TPDU_S_PROCEDURE;
513 break;
514 case TPDU_S_PROCEDURE:
515 if (0x60==byte) { /* wait for next procedure byte */
516 break;
517 } else if (tpdu_packet[1]==byte) { /* get all remaining data bytes */
518 tpdu_state = TPDU_S_DATA_REMAINING;
519 break;
520 } else if ((~tpdu_packet[1])==byte) { /* get single data byte */
521 tpdu_state = TPDU_S_DATA_SINGLE;
522 break;
523 }
524 case TPDU_S_SW1:
525 if ((0x60==(byte&0xf0)) || (0x90==(byte&0xf0))) { /* this procedure byte is SW1 */
526 tpdu_packet[tpdu_packet_i++] = byte;
527 tpdu_state = TPDU_S_SW2;
528 } else {
529 TRACE_WARNING("invalid SW1 0x%02x\n\r", byte);
530 }
531 break;
532 case TPDU_S_SW2:
533 tpdu_packet[tpdu_packet_i++] = byte;
534 print_tpdu(); /* print TPDU for info */
535 change_state(ISO7816_S_WAIT_TPDU); /* this is the end of the TPDU */
536 break;
537 case TPDU_S_DATA_SINGLE:
538 case TPDU_S_DATA_REMAINING:
539 tpdu_packet[tpdu_packet_i++] = byte;
540 if (0==tpdu_packet[4]) {
541 if (5+256<=tpdu_packet_i) {
542 tpdu_state = TPDU_S_SW1;
543 }
544 } else {
545 if (5+tpdu_packet[4]<=tpdu_packet_i) {
546 tpdu_state = TPDU_S_SW1;
547 }
548 }
549 if (TPDU_S_DATA_SINGLE==tpdu_state) {
550 tpdu_state = TPDU_S_PROCEDURE;
551 }
552 break;
553 default:
554 TRACE_ERROR("unhandled TPDU state %u\n\r", tpdu_state);
555 }
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200556}
557
Kévin Redon45ad62d2018-06-07 18:56:41 +0200558static void check_sniffed_data(void)
Kévin Redon36abece2018-06-04 16:30:01 +0200559{
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200560 /* Handle sniffed data */
Kévin Redon7b734622018-06-06 16:13:48 +0200561 while (!rbuf_is_empty(&sniff_buffer)) {
562 uint8_t byte = rbuf_read(&sniff_buffer);
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200563 TRACE_WARNING_WP("< 0x%02x\n\r", byte);
564 switch (iso_state) { /* Handle byte depending on state */
565 case ISO7816_S_RESET: /* During reset we shouldn't receive any data */
566 break;
567 case ISO7816_S_WAIT_ATR: /* After a reset we expect the ATR */
568 change_state(ISO7816_S_IN_ATR); /* go to next state */
569 case ISO7816_S_IN_ATR: /* More ATR data incoming */
570 process_byte_atr(byte);
571 break;
Kévin Redon00ec89d2018-06-27 16:41:52 +0200572 case ISO7816_S_WAIT_TPDU: /* After the ATR we expect TPDU or PPS data */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200573 case ISO7816_S_WAIT_PPS_RSP:
574 if (byte == 0xff) {
575 if (ISO7816_S_WAIT_PPS_RSP==iso_state) {
576 change_state(ISO7816_S_IN_PPS_RSP); /* Go to PPS state */
577 } else {
578 change_state(ISO7816_S_IN_PPS_REQ); /* Go to PPS state */
579 }
580 process_byte_pps(byte);
581 break;
582 }
Kévin Redon00ec89d2018-06-27 16:41:52 +0200583 case ISO7816_S_IN_TPDU: /* More TPDU data incoming */
584 if (ISO7816_S_WAIT_TPDU==iso_state) {
585 change_state(ISO7816_S_IN_TPDU);
586 }
587 process_byte_tpdu(byte);
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200588 break;
589 case ISO7816_S_IN_PPS_REQ:
590 case ISO7816_S_IN_PPS_RSP:
591 process_byte_pps(byte);
592 break;
593 default:
594 TRACE_ERROR("Data received in unknown state %u\n\r", iso_state);
595 }
Kévin Redon7b734622018-06-06 16:13:48 +0200596 }
Kévin Redon36abece2018-06-04 16:30:01 +0200597}
598
Kévin Redond7a6de52018-06-11 13:46:35 +0200599/*! Interrupt Service Routine called on USART activity */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200600void Sniffer_usart_isr(void)
Kévin Redond7a6de52018-06-11 13:46:35 +0200601{
602 /* Read channel status register */
603 uint32_t csr = sniff_usart.base->US_CSR & sniff_usart.base->US_IMR;
604 /* Verify if character has been received */
605 if (csr & US_CSR_RXRDY) {
606 /* Read communication data byte between phone and SIM */
607 uint8_t byte = sniff_usart.base->US_RHR;
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200608 /* Convert convention if required */
609 if (convention_convert) {
610 byte = convention_convert_lut[byte];
611 }
Kévin Redond7a6de52018-06-11 13:46:35 +0200612 /* Store sniffed data into buffer (also clear interrupt */
613 rbuf_write(&sniff_buffer, byte);
614 }
Kévin Redon638cec82018-06-27 16:42:56 +0200615 /* Verify it WT timeout occurred, to detect unresponsive card */
616 if (csr & US_CSR_TIMEOUT) {
617 /* Stop timeout until next character is received */
618 sniff_usart.base->US_CR |= US_CR_STTTO;
619 /* Use timeout to detect end of ATR/PPS/TPDU */
620 switch (iso_state) {
621 case ISO7816_S_RESET:
622 case ISO7816_S_WAIT_ATR:
623 break;
624 case ISO7816_S_IN_ATR:
625 change_state(ISO7816_S_WAIT_ATR);
626 break;
627 case ISO7816_S_WAIT_TPDU:
628 break;
629 case ISO7816_S_WAIT_PPS_RSP:
630 case ISO7816_S_IN_TPDU:
631 case ISO7816_S_IN_PPS_REQ:
632 case ISO7816_S_IN_PPS_RSP:
633 change_state(ISO7816_S_WAIT_TPDU);
634 break;
635 default:
636 break;
637 }
638 }
Kévin Redond7a6de52018-06-11 13:46:35 +0200639}
640
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200641/** PIO interrupt service routine to checks if the card reset line has changed
642 */
643static void Sniffer_reset_isr(const Pin* pPin)
644{
645 /* Ensure an edge on the reset pin cause the interrupt */
646 if (pPin->id!=pin_rst.id || 0==(pPin->mask&pin_rst.mask)) {
647 TRACE_ERROR("Pin other than reset caused a interrupt\n\r");
648 return;
649 }
650 /* Update the ISO state according to the reset change */
651 if (PIO_Get(&pin_rst)) {
652 if (ISO7816_S_WAIT_ATR!=iso_state) {
653 change_state(ISO7816_S_WAIT_ATR);
654 }
655 } else {
656 if (ISO7816_S_RESET!=iso_state) {
657 change_state(ISO7816_S_RESET);
658 }
659 }
660}
661
Kévin Redond7a6de52018-06-11 13:46:35 +0200662/*------------------------------------------------------------------------------
663 * Global functions
664 *------------------------------------------------------------------------------*/
665
666void Sniffer_usart1_irq(void)
667{
668 if (ID_USART1==sniff_usart.id) {
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200669 Sniffer_usart_isr();
Kévin Redond7a6de52018-06-11 13:46:35 +0200670 }
671}
672
673void Sniffer_usart0_irq(void)
674{
675 if (ID_USART0==sniff_usart.id) {
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200676 Sniffer_usart_isr();
Kévin Redond7a6de52018-06-11 13:46:35 +0200677 }
678}
679
Christina Quasta90eefa2015-02-24 17:52:29 +0100680/*-----------------------------------------------------------------------------
Christina Quastd2b05f02015-02-25 18:44:24 +0100681 * Initialization routine
Christina Quasta90eefa2015-02-24 17:52:29 +0100682 *-----------------------------------------------------------------------------*/
Christina Quasta90eefa2015-02-24 17:52:29 +0100683
Harald Welteed75c622017-11-28 21:23:12 +0100684/* Called during USB enumeration after device is enumerated by host */
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100685void Sniffer_configure(void)
Christina Quasta90eefa2015-02-24 17:52:29 +0100686{
Kévin Redon36abece2018-06-04 16:30:01 +0200687 TRACE_INFO("Sniffer config\n\r");
Christina Quasta90eefa2015-02-24 17:52:29 +0100688}
Christina Quastfb524b92015-02-27 13:39:45 +0100689
Harald Welteed75c622017-11-28 21:23:12 +0100690/* called when *different* configuration is set by host */
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100691void Sniffer_exit(void)
Christina Quastfb524b92015-02-27 13:39:45 +0100692{
Kévin Redon36abece2018-06-04 16:30:01 +0200693 TRACE_INFO("Sniffer exit\n\r");
Kévin Redon45ad62d2018-06-07 18:56:41 +0200694 USART_DisableIt(sniff_usart.base, US_IER_RXRDY);
695 /* NOTE: don't forget to set the IRQ according to the USART peripheral used */
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200696 NVIC_DisableIRQ(IRQ_USART_SIM);
Kévin Redon45ad62d2018-06-07 18:56:41 +0200697 USART_SetReceiverEnabled(sniff_usart.base, 0);
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200698
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100699}
700
Kévin Redon36abece2018-06-04 16:30:01 +0200701/* called when *Sniffer* configuration is set by host */
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100702void Sniffer_init(void)
703{
Kévin Redon36abece2018-06-04 16:30:01 +0200704 TRACE_INFO("Sniffer Init\n\r");
Kévin Redon7b734622018-06-06 16:13:48 +0200705
Kévin Redon45ad62d2018-06-07 18:56:41 +0200706 /* Configure pins to sniff communication between phone and card */
707 PIO_Configure(pins_sniff, PIO_LISTSIZE(pins_sniff));
708 /* Configure pins to connect phone to card */
709 PIO_Configure(pins_bus, PIO_LISTSIZE(pins_bus));
710 /* Configure pins to forward phone power to card */
711 PIO_Configure(pins_power, PIO_LISTSIZE(pins_power));
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200712 /* Enable interrupts on port with reset line */
713 NVIC_EnableIRQ(PIOA_IRQn); /* CAUTION this needs to match to the correct port */
714 /* Register ISR to handle card reset change */
715 PIO_ConfigureIt(&pin_rst, &Sniffer_reset_isr);
716 /* Enable interrupt on card reset pin */
717 PIO_EnableIt(&pin_rst);
Kévin Redon45ad62d2018-06-07 18:56:41 +0200718
Kévin Redon7b734622018-06-06 16:13:48 +0200719 /* Clear ring buffer containing the sniffed data */
720 rbuf_reset(&sniff_buffer);
Kévin Redon45ad62d2018-06-07 18:56:41 +0200721 /* Configure USART to as ISO-7816 slave communication to sniff communication */
722 ISO7816_Init(&sniff_usart, CLK_SLAVE);
723 /* Only receive data when sniffing */
724 USART_SetReceiverEnabled(sniff_usart.base, 1);
Kévin Redon638cec82018-06-27 16:42:56 +0200725 /* Enable Receiver time-out WT to detect unresponsive cards */
726 sniff_usart.base->US_RTOR = 9600-12; /* -12 because the timer starts at the end of the 12 ETU frame */
727 /* Enable interrupt to indicate when data has been received or timeout occurred */
728 USART_EnableIt(sniff_usart.base, US_IER_RXRDY | US_IER_TIMEOUT);
Kévin Redond7a6de52018-06-11 13:46:35 +0200729 /* Enable interrupt requests for the USART peripheral */
730 NVIC_EnableIRQ(IRQ_USART_SIM);
731
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200732 /* Reset state */
733 if (ISO7816_S_RESET!=iso_state) {
734 change_state(ISO7816_S_RESET);
735 }
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100736}
737
Kévin Redon8fa6ff52018-06-25 16:00:33 +0200738/* Main (idle/busy) loop of this USB configuration */
Harald Welte7dd3dfd2016-03-03 12:32:04 +0100739void Sniffer_run(void)
740{
Kévin Redon45ad62d2018-06-07 18:56:41 +0200741 check_sniffed_data();
Christina Quastfb524b92015-02-27 13:39:45 +0100742}
Harald Welte2fb59962016-02-28 12:34:26 +0100743#endif /* HAVE_SNIFFER */